├── .github └── workflows │ ├── release-test.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .goreleaser.yml ├── LICENSE ├── Makefile ├── README.md ├── bpf ├── bpf.go ├── bpf_x86_bpfel.go ├── bpf_x86_bpfel.o ├── headers │ ├── bpf_core_read.h │ ├── bpf_endian.h │ ├── bpf_helper_defs.h │ ├── bpf_helpers.h │ ├── bpf_probe_read.h │ ├── bpf_timer.h │ ├── bpf_tracing.h │ ├── errno-base.h │ ├── if_ether_defs.h │ ├── pkt_cls_defs.h │ ├── socket_defs.h │ ├── upai_in6_defs.h │ ├── vmlinux-arm64.h │ ├── vmlinux-riscv.h │ ├── vmlinux-x86.h │ └── vmlinux.h └── ktcpdump.c ├── config.go ├── go.mod ├── go.sum ├── kcore.go ├── kdwarf.go ├── ksym.go ├── main.go └── utils.go /.github/workflows/release-test.yml: -------------------------------------------------------------------------------- 1 | name: release-test 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ "main" ] 7 | pull_request: 8 | branches: [ "main" ] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | 15 | release-test: 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 5 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: '1.23.2' 25 | 26 | - name: Set up deps 27 | run: | 28 | sudo apt-get install -y gcc flex bison make autoconf libelf-dev 29 | git submodule update --init --recursive 30 | sudo make libpcap LIBPCAP_DIST_DIR=/usr/local CARCH=x86_64 31 | 32 | 33 | - name: Run GoReleaser 34 | uses: goreleaser/goreleaser-action@v6 35 | with: 36 | distribution: goreleaser 37 | version: '~> v2' 38 | args: release --snapshot --clean --skip=publish -p 1 39 | 40 | - name: Store Releases 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: ktcpdump_v0.0.0-next_linux_amd64.tar.gz 44 | path: dist/ktcpdump_v0.0.0-next_linux_amd64.tar.gz 45 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - v* 8 | 9 | jobs: 10 | goreleaser: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 5 13 | permissions: 14 | contents: write 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: '1.23.2' 25 | env: 26 | GOPATH: ${{ env.HOME }} 27 | 28 | - name: Set up deps 29 | run: | 30 | sudo apt-get install -y gcc flex bison make autoconf libelf-dev 31 | git submodule update --init --recursive 32 | sudo make libpcap LIBPCAP_DIST_DIR=/usr/local CARCH=x86_64 33 | 34 | 35 | - name: Run GoReleaser 36 | uses: goreleaser/goreleaser-action@v6 37 | with: 38 | version: '~> v2' 39 | args: release --clean -p 1 40 | env: 41 | GOPATH: ${{ env.HOME }} 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | 24 | # env file 25 | .env 26 | 27 | tags 28 | ktcpdump 29 | /output/ 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libpcap"] 2 | path = libpcap 3 | url = https://github.com/the-tcpdump-group/libpcap.git 4 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - id: ktcpdump-amd64 3 | binary: ktcpdump 4 | env: 5 | - CGO_ENABLED=1 6 | - CC=gcc 7 | flags: 8 | - -tags=static 9 | ldflags: 10 | - -linkmode 'external' 11 | - -extldflags "-static" 12 | goos: 13 | - linux 14 | goarch: 15 | - amd64 16 | 17 | archives: 18 | - builds: 19 | - ktcpdump-amd64 20 | 21 | release: 22 | prerelease: auto 23 | 24 | snapshot: 25 | name_template: "{{ .Tag }}-next" 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ./gray 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .ONESHELL: 2 | # .SHELLFLAGS = -e 3 | SHELL = /bin/sh 4 | 5 | GIT = $(shell which git || /bin/false) 6 | OUTPUT = ./output 7 | 8 | BPF_SRC = ./bpf 9 | LIBPCAP = ./libpcap 10 | LIBPCAP_SRC = $(abspath $(LIBPCAP)) 11 | LIBPCAP_DIST_DIR ?= $(abspath $(OUTPUT)/libpcap) 12 | LIBPCAP_HEADER_DIR = $(abspath $(LIBPCAP_DIST_DIR)/include) 13 | LIBPCAP_OBJ_DIR = $(abspath $(LIBPCAP_DIST_DIR)/lib) 14 | LIBPCAP_OBJ = $(abspath $(LIBPCAP_OBJ_DIR)/libpcap.a) 15 | 16 | GIT_COMMIT ?= $(shell git rev-parse --short HEAD) 17 | VERSION ?= $(shell git describe --tags --abbrev=0) 18 | CGO_CFLAGS_STATIC = "-I$(LIBPCAP_HEADER_DIR)" 19 | CGO_LDFLAGS_STATIC = "-L$(LIBPCAP_OBJ_DIR) -lpcap $(LIBPCAP_OBJ)" 20 | CGO_ENABLED ?= 1 21 | GOARCH ?= $(shell go env GOARCH) 22 | GOOS ?= $(shell go env GOOS) 23 | LDFLAGS := -linkmode "external" -extldflags "-static" 24 | 25 | CARCH ?= $(shell uname -m) 26 | LIBPCAP_ARCH = $(CARCH)-unknown-linux-gnu 27 | LIBPCAP_CC ?= gcc 28 | 29 | .PHONY: libpcap 30 | libpcap: $(LIBPCAP_OBJ) 31 | 32 | $(LIBPCAP_OBJ): $(LIBPCAP_SRC)/pcap.h $(wildcard $(LIBPCAP_SRC)/*.[ch]) | $(LIBPCAP_DIST_DIR) 33 | cd $(LIBPCAP_SRC) && \ 34 | sh autogen.sh && \ 35 | CC=$(LIBPCAP_CC) ./configure --disable-shared --disable-usb --disable-netmap --disable-bluetooth --disable-dbus --without-libnl \ 36 | --disable-rdma --host=$(LIBPCAP_ARCH) && \ 37 | $(MAKE) && \ 38 | $(MAKE) install prefix=$(LIBPCAP_DIST_DIR) 39 | 40 | $(LIBPCAP_SRC)/pcap.h: 41 | ifeq ($(wildcard $@), ) 42 | echo "INFO: updating submodule 'libpcap'" 43 | $(GIT) submodule update --init --recursive 44 | endif 45 | 46 | $(LIBPCAP_DIST_DIR): $(LIBPCAP_SRC) 47 | 48 | $(OUTPUT): 49 | mkdir -p $(OUTPUT) 50 | 51 | 52 | .PHONY: build 53 | build: libpcap 54 | CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \ 55 | CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \ 56 | CGO_ENABLED=1 go build -tags static -ldflags "$(LDFLAGS)" 57 | 58 | 59 | .PHONY: test 60 | test: 61 | CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \ 62 | CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \ 63 | CGO_ENABLED=1 go test -v ./... 64 | 65 | 66 | .PHONY: build-bpf 67 | build-bpf: 68 | go generate ./... 69 | 70 | 71 | .PHONY: clean 72 | clean: 73 | $(MAKE) -C $(LIBPCAP_SRC) clean 74 | rm -rf $(OUTPUT) 75 | rm -f ./ktcpdump 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ktcpdump 2 | 3 | 4 | ktcpdump is a network debugging tool developed using eBPF technology. 5 | Its key feature is that you can debug network-related functions in the Linux kernel **line by line**. 6 | 7 | 8 | 9 | ## Installation 10 | 11 | Please download the latest binary in the [releases](https://github.com/jschwinger233/ktcpdump/releases). 12 | 13 | 14 | ## Requirements 15 | 16 | * Linux kernel version must be larger than 5.5. 17 | * Installed debug symbol for linux image: 18 | 19 | ``` 20 | # follow https://documentation.ubuntu.com/server/reference/debugging/debug-symbol-packages/ 21 | sudo apt-get install linux-image-`uname -r`-dbgsym 22 | ``` 23 | 24 | 25 | ## Usage 26 | 27 | ``` 28 | ktcpdump [ -i kfunc ] [ -w file ] [ -d vmlinux-dbg ] [ -v ] expresssion 29 | -d, --d string path to debug image 30 | -h, --help 31 | -i, --i strings symbol|symbol+offset|address (default [ip_rcv,dev_hard_start_xmit]) 32 | -v, --v verbose output 33 | -w, --w string write packets to a file (default "/tmp/a.pcap") 34 | 35 | ``` 36 | 37 | 38 | ### Example commands 39 | 40 | 41 | ``` 42 | $ sudo ktcpdump -i 'tc_run+*' -d /usr/lib/debug/boot/vmlinux-`uname -r` 'dst host 1.1.1.1 and icmp' 43 | no skb skb->len pc ksym addr2line 44 | 1 ffff97720b2cc900 98 ffffffff92af9281 tc_run+1 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3927 45 | 2 ffff97720b2cc900 98 ffffffff92af92a7 tc_run+39 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3931 46 | 3 ffff97720b2cc900 98 ffffffff92af92b8 tc_run+56 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3930 47 | 4 ffff97720b2cc900 98 ffffffff92af92bb tc_run+59 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3933 48 | 5 ffff97720b2cc900 98 ffffffff92af92c4 tc_run+68 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3936 49 | 6 ffff97720b2cc900 98 ffffffff92af92c6 tc_run+70 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3937 50 | 7 ffff97720b2cc900 98 ffffffff92af92cd tc_run+77 /build/linux-vCyKs5/linux-6.8.0/include/net/sch_generic.h:1060 51 | 8 ffff97720b2cc900 98 ffffffff92af92d4 tc_run+84 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3938 52 | 9 ffff97720b2cc900 98 ffffffff92af92db tc_run+91 /build/linux-vCyKs5/linux-6.8.0/include/linux/skbuff.h:1605 53 | 10 ffff97720b2cc900 98 ffffffff92af92e8 tc_run+104 /build/linux-vCyKs5/linux-6.8.0/include/net/sch_generic.h:1072 54 | 11 ffff97720b2cc900 98 ffffffff92af92eb tc_run+107 /build/linux-vCyKs5/linux-6.8.0/include/net/sch_generic.h:1325 55 | 12 ffff97720b2cc900 98 ffffffff92af92f8 tc_run+120 /build/linux-vCyKs5/linux-6.8.0/include/net/sch_generic.h:863 56 | 13 ffff97720b2cc900 98 ffffffff92af9306 tc_run+134 /build/linux-vCyKs5/linux-6.8.0/arch/x86/include/asm/local.h:33 57 | 14 ffff97720b2cc900 98 ffffffff92af930d tc_run+141 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3941 58 | 15 ffff97720b2cc900 98 ffffffff92af9324 tc_run+164 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3943 59 | 16 ffff97720b2cc900 98 ffffffff92af933e tc_run+190 /build/linux-vCyKs5/linux-6.8.0/net/core/dev.c:3955 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /bpf/bpf.go: -------------------------------------------------------------------------------- 1 | package bpf 2 | 3 | //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-15 -no-strip -target native -type event Bpf ./ktcpdump.c -- -I./headers -I. -Wall 4 | -------------------------------------------------------------------------------- /bpf/bpf_x86_bpfel.go: -------------------------------------------------------------------------------- 1 | // Code generated by bpf2go; DO NOT EDIT. 2 | //go:build 386 || amd64 3 | 4 | package bpf 5 | 6 | import ( 7 | "bytes" 8 | _ "embed" 9 | "fmt" 10 | "io" 11 | 12 | "github.com/cilium/ebpf" 13 | ) 14 | 15 | type BpfEvent struct { 16 | At uint64 17 | Ts uint64 18 | Skb uint64 19 | Call uint64 20 | DataLen uint32 21 | Protocol uint16 22 | HasMac uint8 23 | Dev [16]uint8 24 | _ [1]byte 25 | } 26 | 27 | // LoadBpf returns the embedded CollectionSpec for Bpf. 28 | func LoadBpf() (*ebpf.CollectionSpec, error) { 29 | reader := bytes.NewReader(_BpfBytes) 30 | spec, err := ebpf.LoadCollectionSpecFromReader(reader) 31 | if err != nil { 32 | return nil, fmt.Errorf("can't load Bpf: %w", err) 33 | } 34 | 35 | return spec, err 36 | } 37 | 38 | // LoadBpfObjects loads Bpf and converts it into a struct. 39 | // 40 | // The following types are suitable as obj argument: 41 | // 42 | // *BpfObjects 43 | // *BpfPrograms 44 | // *BpfMaps 45 | // 46 | // See ebpf.CollectionSpec.LoadAndAssign documentation for details. 47 | func LoadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { 48 | spec, err := LoadBpf() 49 | if err != nil { 50 | return err 51 | } 52 | 53 | return spec.LoadAndAssign(obj, opts) 54 | } 55 | 56 | // BpfSpecs contains maps and programs before they are loaded into the kernel. 57 | // 58 | // It can be passed ebpf.CollectionSpec.Assign. 59 | type BpfSpecs struct { 60 | BpfProgramSpecs 61 | BpfMapSpecs 62 | } 63 | 64 | // BpfSpecs contains programs before they are loaded into the kernel. 65 | // 66 | // It can be passed ebpf.CollectionSpec.Assign. 67 | type BpfProgramSpecs struct { 68 | KprobeSkbBySearch *ebpf.ProgramSpec `ebpf:"kprobe_skb_by_search"` 69 | KprobeSkbFree *ebpf.ProgramSpec `ebpf:"kprobe_skb_free"` 70 | KretprobeSkbBuild *ebpf.ProgramSpec `ebpf:"kretprobe_skb_build"` 71 | } 72 | 73 | // BpfMapSpecs contains maps before they are loaded into the kernel. 74 | // 75 | // It can be passed ebpf.CollectionSpec.Assign. 76 | type BpfMapSpecs struct { 77 | AliveSkbs *ebpf.MapSpec `ebpf:"alive_skbs"` 78 | EventRingbuf *ebpf.MapSpec `ebpf:"event_ringbuf"` 79 | RingbufData *ebpf.MapSpec `ebpf:"ringbuf_data"` 80 | } 81 | 82 | // BpfObjects contains all objects after they have been loaded into the kernel. 83 | // 84 | // It can be passed to LoadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. 85 | type BpfObjects struct { 86 | BpfPrograms 87 | BpfMaps 88 | } 89 | 90 | func (o *BpfObjects) Close() error { 91 | return _BpfClose( 92 | &o.BpfPrograms, 93 | &o.BpfMaps, 94 | ) 95 | } 96 | 97 | // BpfMaps contains all maps after they have been loaded into the kernel. 98 | // 99 | // It can be passed to LoadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. 100 | type BpfMaps struct { 101 | AliveSkbs *ebpf.Map `ebpf:"alive_skbs"` 102 | EventRingbuf *ebpf.Map `ebpf:"event_ringbuf"` 103 | RingbufData *ebpf.Map `ebpf:"ringbuf_data"` 104 | } 105 | 106 | func (m *BpfMaps) Close() error { 107 | return _BpfClose( 108 | m.AliveSkbs, 109 | m.EventRingbuf, 110 | m.RingbufData, 111 | ) 112 | } 113 | 114 | // BpfPrograms contains all programs after they have been loaded into the kernel. 115 | // 116 | // It can be passed to LoadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. 117 | type BpfPrograms struct { 118 | KprobeSkbBySearch *ebpf.Program `ebpf:"kprobe_skb_by_search"` 119 | KprobeSkbFree *ebpf.Program `ebpf:"kprobe_skb_free"` 120 | KretprobeSkbBuild *ebpf.Program `ebpf:"kretprobe_skb_build"` 121 | } 122 | 123 | func (p *BpfPrograms) Close() error { 124 | return _BpfClose( 125 | p.KprobeSkbBySearch, 126 | p.KprobeSkbFree, 127 | p.KretprobeSkbBuild, 128 | ) 129 | } 130 | 131 | func _BpfClose(closers ...io.Closer) error { 132 | for _, closer := range closers { 133 | if err := closer.Close(); err != nil { 134 | return err 135 | } 136 | } 137 | return nil 138 | } 139 | 140 | // Do not access this directly. 141 | // 142 | //go:embed bpf_x86_bpfel.o 143 | var _BpfBytes []byte 144 | -------------------------------------------------------------------------------- /bpf/bpf_x86_bpfel.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jschwinger233/ktcpdump/592e2d303bdf99236340e3eba12fc76838be9403/bpf/bpf_x86_bpfel.o -------------------------------------------------------------------------------- /bpf/headers/bpf_core_read.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __BPF_CORE_READ_H__ 3 | #define __BPF_CORE_READ_H__ 4 | 5 | /* 6 | * enum bpf_field_info_kind is passed as a second argument into 7 | * __builtin_preserve_field_info() built-in to get a specific aspect of 8 | * a field, captured as a first argument. __builtin_preserve_field_info(field, 9 | * info_kind) returns __u32 integer and produces BTF field relocation, which 10 | * is understood and processed by libbpf during BPF object loading. See 11 | * selftests/bpf for examples. 12 | */ 13 | enum bpf_field_info_kind { 14 | BPF_FIELD_BYTE_OFFSET = 0, /* field byte offset */ 15 | BPF_FIELD_BYTE_SIZE = 1, 16 | BPF_FIELD_EXISTS = 2, /* field existence in target kernel */ 17 | BPF_FIELD_SIGNED = 3, 18 | BPF_FIELD_LSHIFT_U64 = 4, 19 | BPF_FIELD_RSHIFT_U64 = 5, 20 | }; 21 | 22 | /* second argument to __builtin_btf_type_id() built-in */ 23 | enum bpf_type_id_kind { 24 | BPF_TYPE_ID_LOCAL = 0, /* BTF type ID in local program */ 25 | BPF_TYPE_ID_TARGET = 1, /* BTF type ID in target kernel */ 26 | }; 27 | 28 | /* second argument to __builtin_preserve_type_info() built-in */ 29 | enum bpf_type_info_kind { 30 | BPF_TYPE_EXISTS = 0, /* type existence in target kernel */ 31 | BPF_TYPE_SIZE = 1, /* type size in target kernel */ 32 | BPF_TYPE_MATCHES = 2, /* type match in target kernel */ 33 | }; 34 | 35 | /* second argument to __builtin_preserve_enum_value() built-in */ 36 | enum bpf_enum_value_kind { 37 | BPF_ENUMVAL_EXISTS = 0, /* enum value existence in kernel */ 38 | BPF_ENUMVAL_VALUE = 1, /* enum value value relocation */ 39 | }; 40 | 41 | #define __CORE_RELO(src, field, info) \ 42 | __builtin_preserve_field_info((src)->field, BPF_FIELD_##info) 43 | 44 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 45 | #define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \ 46 | bpf_probe_read_kernel( \ 47 | (void *)dst, \ 48 | __CORE_RELO(src, fld, BYTE_SIZE), \ 49 | (const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET)) 50 | #else 51 | /* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so 52 | * for big-endian we need to adjust destination pointer accordingly, based on 53 | * field byte size 54 | */ 55 | #define __CORE_BITFIELD_PROBE_READ(dst, src, fld) \ 56 | bpf_probe_read_kernel( \ 57 | (void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \ 58 | __CORE_RELO(src, fld, BYTE_SIZE), \ 59 | (const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET)) 60 | #endif 61 | 62 | /* 63 | * Extract bitfield, identified by s->field, and return its value as u64. 64 | * All this is done in relocatable manner, so bitfield changes such as 65 | * signedness, bit size, offset changes, this will be handled automatically. 66 | * This version of macro is using bpf_probe_read_kernel() to read underlying 67 | * integer storage. Macro functions as an expression and its return type is 68 | * bpf_probe_read_kernel()'s return value: 0, on success, <0 on error. 69 | */ 70 | #define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({ \ 71 | unsigned long long val = 0; \ 72 | \ 73 | __CORE_BITFIELD_PROBE_READ(&val, s, field); \ 74 | val <<= __CORE_RELO(s, field, LSHIFT_U64); \ 75 | if (__CORE_RELO(s, field, SIGNED)) \ 76 | val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \ 77 | else \ 78 | val = val >> __CORE_RELO(s, field, RSHIFT_U64); \ 79 | val; \ 80 | }) 81 | 82 | /* 83 | * Extract bitfield, identified by s->field, and return its value as u64. 84 | * This version of macro is using direct memory reads and should be used from 85 | * BPF program types that support such functionality (e.g., typed raw 86 | * tracepoints). 87 | */ 88 | #define BPF_CORE_READ_BITFIELD(s, field) ({ \ 89 | const void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \ 90 | unsigned long long val; \ 91 | \ 92 | /* This is a so-called barrier_var() operation that makes specified \ 93 | * variable "a black box" for optimizing compiler. \ 94 | * It forces compiler to perform BYTE_OFFSET relocation on p and use \ 95 | * its calculated value in the switch below, instead of applying \ 96 | * the same relocation 4 times for each individual memory load. \ 97 | */ \ 98 | asm volatile("" : "=r"(p) : "0"(p)); \ 99 | \ 100 | switch (__CORE_RELO(s, field, BYTE_SIZE)) { \ 101 | case 1: val = *(const unsigned char *)p; break; \ 102 | case 2: val = *(const unsigned short *)p; break; \ 103 | case 4: val = *(const unsigned int *)p; break; \ 104 | case 8: val = *(const unsigned long long *)p; break; \ 105 | } \ 106 | val <<= __CORE_RELO(s, field, LSHIFT_U64); \ 107 | if (__CORE_RELO(s, field, SIGNED)) \ 108 | val = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64); \ 109 | else \ 110 | val = val >> __CORE_RELO(s, field, RSHIFT_U64); \ 111 | val; \ 112 | }) 113 | 114 | #define ___bpf_field_ref1(field) (field) 115 | #define ___bpf_field_ref2(type, field) (((typeof(type) *)0)->field) 116 | #define ___bpf_field_ref(args...) \ 117 | ___bpf_apply(___bpf_field_ref, ___bpf_narg(args))(args) 118 | 119 | /* 120 | * Convenience macro to check that field actually exists in target kernel's. 121 | * Returns: 122 | * 1, if matching field is present in target kernel; 123 | * 0, if no matching field found. 124 | * 125 | * Supports two forms: 126 | * - field reference through variable access: 127 | * bpf_core_field_exists(p->my_field); 128 | * - field reference through type and field names: 129 | * bpf_core_field_exists(struct my_type, my_field). 130 | */ 131 | #define bpf_core_field_exists(field...) \ 132 | __builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_EXISTS) 133 | 134 | /* 135 | * Convenience macro to get the byte size of a field. Works for integers, 136 | * struct/unions, pointers, arrays, and enums. 137 | * 138 | * Supports two forms: 139 | * - field reference through variable access: 140 | * bpf_core_field_size(p->my_field); 141 | * - field reference through type and field names: 142 | * bpf_core_field_size(struct my_type, my_field). 143 | */ 144 | #define bpf_core_field_size(field...) \ 145 | __builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_SIZE) 146 | 147 | /* 148 | * Convenience macro to get field's byte offset. 149 | * 150 | * Supports two forms: 151 | * - field reference through variable access: 152 | * bpf_core_field_offset(p->my_field); 153 | * - field reference through type and field names: 154 | * bpf_core_field_offset(struct my_type, my_field). 155 | */ 156 | #define bpf_core_field_offset(field...) \ 157 | __builtin_preserve_field_info(___bpf_field_ref(field), BPF_FIELD_BYTE_OFFSET) 158 | 159 | /* 160 | * Convenience macro to get BTF type ID of a specified type, using a local BTF 161 | * information. Return 32-bit unsigned integer with type ID from program's own 162 | * BTF. Always succeeds. 163 | */ 164 | #define bpf_core_type_id_local(type) \ 165 | __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL) 166 | 167 | /* 168 | * Convenience macro to get BTF type ID of a target kernel's type that matches 169 | * specified local type. 170 | * Returns: 171 | * - valid 32-bit unsigned type ID in kernel BTF; 172 | * - 0, if no matching type was found in a target kernel BTF. 173 | */ 174 | #define bpf_core_type_id_kernel(type) \ 175 | __builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET) 176 | 177 | /* 178 | * Convenience macro to check that provided named type 179 | * (struct/union/enum/typedef) exists in a target kernel. 180 | * Returns: 181 | * 1, if such type is present in target kernel's BTF; 182 | * 0, if no matching type is found. 183 | */ 184 | #define bpf_core_type_exists(type) \ 185 | __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS) 186 | 187 | /* 188 | * Convenience macro to check that provided named type 189 | * (struct/union/enum/typedef) "matches" that in a target kernel. 190 | * Returns: 191 | * 1, if the type matches in the target kernel's BTF; 192 | * 0, if the type does not match any in the target kernel 193 | */ 194 | #define bpf_core_type_matches(type) \ 195 | __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_MATCHES) 196 | 197 | /* 198 | * Convenience macro to get the byte size of a provided named type 199 | * (struct/union/enum/typedef) in a target kernel. 200 | * Returns: 201 | * >= 0 size (in bytes), if type is present in target kernel's BTF; 202 | * 0, if no matching type is found. 203 | */ 204 | #define bpf_core_type_size(type) \ 205 | __builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE) 206 | 207 | /* 208 | * Convenience macro to check that provided enumerator value is defined in 209 | * a target kernel. 210 | * Returns: 211 | * 1, if specified enum type and its enumerator value are present in target 212 | * kernel's BTF; 213 | * 0, if no matching enum and/or enum value within that enum is found. 214 | */ 215 | #define bpf_core_enum_value_exists(enum_type, enum_value) \ 216 | __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS) 217 | 218 | /* 219 | * Convenience macro to get the integer value of an enumerator value in 220 | * a target kernel. 221 | * Returns: 222 | * 64-bit value, if specified enum type and its enumerator value are 223 | * present in target kernel's BTF; 224 | * 0, if no matching enum and/or enum value within that enum is found. 225 | */ 226 | #define bpf_core_enum_value(enum_type, enum_value) \ 227 | __builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE) 228 | 229 | /* 230 | * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures 231 | * offset relocation for source address using __builtin_preserve_access_index() 232 | * built-in, provided by Clang. 233 | * 234 | * __builtin_preserve_access_index() takes as an argument an expression of 235 | * taking an address of a field within struct/union. It makes compiler emit 236 | * a relocation, which records BTF type ID describing root struct/union and an 237 | * accessor string which describes exact embedded field that was used to take 238 | * an address. See detailed description of this relocation format and 239 | * semantics in comments to struct bpf_field_reloc in libbpf_internal.h. 240 | * 241 | * This relocation allows libbpf to adjust BPF instruction to use correct 242 | * actual field offset, based on target kernel BTF type that matches original 243 | * (local) BTF, used to record relocation. 244 | */ 245 | #define bpf_core_read(dst, sz, src) \ 246 | bpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src)) 247 | 248 | /* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */ 249 | #define bpf_core_read_user(dst, sz, src) \ 250 | bpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src)) 251 | /* 252 | * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str() 253 | * additionally emitting BPF CO-RE field relocation for specified source 254 | * argument. 255 | */ 256 | #define bpf_core_read_str(dst, sz, src) \ 257 | bpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src)) 258 | 259 | /* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */ 260 | #define bpf_core_read_user_str(dst, sz, src) \ 261 | bpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src)) 262 | 263 | #define ___concat(a, b) a ## b 264 | #define ___apply(fn, n) ___concat(fn, n) 265 | #define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N 266 | 267 | /* 268 | * return number of provided arguments; used for switch-based variadic macro 269 | * definitions (see ___last, ___arrow, etc below) 270 | */ 271 | #define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 272 | /* 273 | * return 0 if no arguments are passed, N - otherwise; used for 274 | * recursively-defined macros to specify termination (0) case, and generic 275 | * (N) case (e.g., ___read_ptrs, ___core_read) 276 | */ 277 | #define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0) 278 | 279 | #define ___last1(x) x 280 | #define ___last2(a, x) x 281 | #define ___last3(a, b, x) x 282 | #define ___last4(a, b, c, x) x 283 | #define ___last5(a, b, c, d, x) x 284 | #define ___last6(a, b, c, d, e, x) x 285 | #define ___last7(a, b, c, d, e, f, x) x 286 | #define ___last8(a, b, c, d, e, f, g, x) x 287 | #define ___last9(a, b, c, d, e, f, g, h, x) x 288 | #define ___last10(a, b, c, d, e, f, g, h, i, x) x 289 | #define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__) 290 | 291 | #define ___nolast2(a, _) a 292 | #define ___nolast3(a, b, _) a, b 293 | #define ___nolast4(a, b, c, _) a, b, c 294 | #define ___nolast5(a, b, c, d, _) a, b, c, d 295 | #define ___nolast6(a, b, c, d, e, _) a, b, c, d, e 296 | #define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f 297 | #define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g 298 | #define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h 299 | #define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i 300 | #define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__) 301 | 302 | #define ___arrow1(a) a 303 | #define ___arrow2(a, b) a->b 304 | #define ___arrow3(a, b, c) a->b->c 305 | #define ___arrow4(a, b, c, d) a->b->c->d 306 | #define ___arrow5(a, b, c, d, e) a->b->c->d->e 307 | #define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f 308 | #define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g 309 | #define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h 310 | #define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i 311 | #define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j 312 | #define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__) 313 | 314 | #define ___type(...) typeof(___arrow(__VA_ARGS__)) 315 | 316 | #define ___read(read_fn, dst, src_type, src, accessor) \ 317 | read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor) 318 | 319 | /* "recursively" read a sequence of inner pointers using local __t var */ 320 | #define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a); 321 | #define ___rd_last(fn, ...) \ 322 | ___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__)); 323 | #define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__) 324 | #define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 325 | #define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 326 | #define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 327 | #define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 328 | #define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 329 | #define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 330 | #define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 331 | #define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 332 | #define ___read_ptrs(fn, src, ...) \ 333 | ___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__) 334 | 335 | #define ___core_read0(fn, fn_ptr, dst, src, a) \ 336 | ___read(fn, dst, ___type(src), src, a); 337 | #define ___core_readN(fn, fn_ptr, dst, src, ...) \ 338 | ___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__)) \ 339 | ___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \ 340 | ___last(__VA_ARGS__)); 341 | #define ___core_read(fn, fn_ptr, dst, src, a, ...) \ 342 | ___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst, \ 343 | src, a, ##__VA_ARGS__) 344 | 345 | /* 346 | * BPF_CORE_READ_INTO() is a more performance-conscious variant of 347 | * BPF_CORE_READ(), in which final field is read into user-provided storage. 348 | * See BPF_CORE_READ() below for more details on general usage. 349 | */ 350 | #define BPF_CORE_READ_INTO(dst, src, a, ...) ({ \ 351 | ___core_read(bpf_core_read, bpf_core_read, \ 352 | dst, (src), a, ##__VA_ARGS__) \ 353 | }) 354 | 355 | /* 356 | * Variant of BPF_CORE_READ_INTO() for reading from user-space memory. 357 | * 358 | * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. 359 | */ 360 | #define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({ \ 361 | ___core_read(bpf_core_read_user, bpf_core_read_user, \ 362 | dst, (src), a, ##__VA_ARGS__) \ 363 | }) 364 | 365 | /* Non-CO-RE variant of BPF_CORE_READ_INTO() */ 366 | #define BPF_PROBE_READ_INTO(dst, src, a, ...) ({ \ 367 | ___core_read(bpf_probe_read_kernel, bpf_probe_read_kernel, \ 368 | dst, (src), a, ##__VA_ARGS__) \ 369 | }) 370 | 371 | /* Non-CO-RE variant of BPF_CORE_READ_USER_INTO(). 372 | * 373 | * As no CO-RE relocations are emitted, source types can be arbitrary and are 374 | * not restricted to kernel types only. 375 | */ 376 | #define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({ \ 377 | ___core_read(bpf_probe_read_user, bpf_probe_read_user, \ 378 | dst, (src), a, ##__VA_ARGS__) \ 379 | }) 380 | 381 | /* 382 | * BPF_CORE_READ_STR_INTO() does same "pointer chasing" as 383 | * BPF_CORE_READ() for intermediate pointers, but then executes (and returns 384 | * corresponding error code) bpf_core_read_str() for final string read. 385 | */ 386 | #define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({ \ 387 | ___core_read(bpf_core_read_str, bpf_core_read, \ 388 | dst, (src), a, ##__VA_ARGS__) \ 389 | }) 390 | 391 | /* 392 | * Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory. 393 | * 394 | * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. 395 | */ 396 | #define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({ \ 397 | ___core_read(bpf_core_read_user_str, bpf_core_read_user, \ 398 | dst, (src), a, ##__VA_ARGS__) \ 399 | }) 400 | 401 | /* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */ 402 | #define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({ \ 403 | ___core_read(bpf_probe_read_kernel_str, bpf_probe_read_kernel, \ 404 | dst, (src), a, ##__VA_ARGS__) \ 405 | }) 406 | 407 | /* 408 | * Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO(). 409 | * 410 | * As no CO-RE relocations are emitted, source types can be arbitrary and are 411 | * not restricted to kernel types only. 412 | */ 413 | #define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({ \ 414 | ___core_read(bpf_probe_read_user_str, bpf_probe_read_user, \ 415 | dst, (src), a, ##__VA_ARGS__) \ 416 | }) 417 | 418 | /* 419 | * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially 420 | * when there are few pointer chasing steps. 421 | * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like: 422 | * int x = s->a.b.c->d.e->f->g; 423 | * can be succinctly achieved using BPF_CORE_READ as: 424 | * int x = BPF_CORE_READ(s, a.b.c, d.e, f, g); 425 | * 426 | * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF 427 | * CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically 428 | * equivalent to: 429 | * 1. const void *__t = s->a.b.c; 430 | * 2. __t = __t->d.e; 431 | * 3. __t = __t->f; 432 | * 4. return __t->g; 433 | * 434 | * Equivalence is logical, because there is a heavy type casting/preservation 435 | * involved, as well as all the reads are happening through 436 | * bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to 437 | * emit CO-RE relocations. 438 | * 439 | * N.B. Only up to 9 "field accessors" are supported, which should be more 440 | * than enough for any practical purpose. 441 | */ 442 | #define BPF_CORE_READ(src, a, ...) ({ \ 443 | ___type((src), a, ##__VA_ARGS__) __r; \ 444 | BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \ 445 | __r; \ 446 | }) 447 | 448 | /* 449 | * Variant of BPF_CORE_READ() for reading from user-space memory. 450 | * 451 | * NOTE: all the source types involved are still *kernel types* and need to 452 | * exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will 453 | * fail. Custom user types are not relocatable with CO-RE. 454 | * The typical situation in which BPF_CORE_READ_USER() might be used is to 455 | * read kernel UAPI types from the user-space memory passed in as a syscall 456 | * input argument. 457 | */ 458 | #define BPF_CORE_READ_USER(src, a, ...) ({ \ 459 | ___type((src), a, ##__VA_ARGS__) __r; \ 460 | BPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \ 461 | __r; \ 462 | }) 463 | 464 | /* Non-CO-RE variant of BPF_CORE_READ() */ 465 | #define BPF_PROBE_READ(src, a, ...) ({ \ 466 | ___type((src), a, ##__VA_ARGS__) __r; \ 467 | BPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \ 468 | __r; \ 469 | }) 470 | 471 | /* 472 | * Non-CO-RE variant of BPF_CORE_READ_USER(). 473 | * 474 | * As no CO-RE relocations are emitted, source types can be arbitrary and are 475 | * not restricted to kernel types only. 476 | */ 477 | #define BPF_PROBE_READ_USER(src, a, ...) ({ \ 478 | ___type((src), a, ##__VA_ARGS__) __r; \ 479 | BPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__); \ 480 | __r; \ 481 | }) 482 | 483 | #endif 484 | 485 | -------------------------------------------------------------------------------- /bpf/headers/bpf_endian.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __BPF_ENDIAN__ 3 | #define __BPF_ENDIAN__ 4 | 5 | /* 6 | * Isolate byte #n and put it into byte #m, for __u##b type. 7 | * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64: 8 | * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 9 | * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000 10 | * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 11 | * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000 12 | */ 13 | #define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8)) 14 | 15 | #define ___bpf_swab16(x) ((__u16)( \ 16 | ___bpf_mvb(x, 16, 0, 1) | \ 17 | ___bpf_mvb(x, 16, 1, 0))) 18 | 19 | #define ___bpf_swab32(x) ((__u32)( \ 20 | ___bpf_mvb(x, 32, 0, 3) | \ 21 | ___bpf_mvb(x, 32, 1, 2) | \ 22 | ___bpf_mvb(x, 32, 2, 1) | \ 23 | ___bpf_mvb(x, 32, 3, 0))) 24 | 25 | #define ___bpf_swab64(x) ((__u64)( \ 26 | ___bpf_mvb(x, 64, 0, 7) | \ 27 | ___bpf_mvb(x, 64, 1, 6) | \ 28 | ___bpf_mvb(x, 64, 2, 5) | \ 29 | ___bpf_mvb(x, 64, 3, 4) | \ 30 | ___bpf_mvb(x, 64, 4, 3) | \ 31 | ___bpf_mvb(x, 64, 5, 2) | \ 32 | ___bpf_mvb(x, 64, 6, 1) | \ 33 | ___bpf_mvb(x, 64, 7, 0))) 34 | 35 | /* LLVM's BPF target selects the endianness of the CPU 36 | * it compiles on, or the user specifies (bpfel/bpfeb), 37 | * respectively. The used __BYTE_ORDER__ is defined by 38 | * the compiler, we cannot rely on __BYTE_ORDER from 39 | * libc headers, since it doesn't reflect the actual 40 | * requested byte order. 41 | * 42 | * Note, LLVM's BPF target has different __builtin_bswapX() 43 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE 44 | * in bpfel and bpfeb case, which means below, that we map 45 | * to cpu_to_be16(). We could use it unconditionally in BPF 46 | * case, but better not rely on it, so that this header here 47 | * can be used from application and BPF program side, which 48 | * use different targets. 49 | */ 50 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 51 | # define __bpf_ntohs(x) __builtin_bswap16(x) 52 | # define __bpf_htons(x) __builtin_bswap16(x) 53 | # define __bpf_constant_ntohs(x) ___bpf_swab16(x) 54 | # define __bpf_constant_htons(x) ___bpf_swab16(x) 55 | # define __bpf_ntohl(x) __builtin_bswap32(x) 56 | # define __bpf_htonl(x) __builtin_bswap32(x) 57 | # define __bpf_constant_ntohl(x) ___bpf_swab32(x) 58 | # define __bpf_constant_htonl(x) ___bpf_swab32(x) 59 | # define __bpf_be64_to_cpu(x) __builtin_bswap64(x) 60 | # define __bpf_cpu_to_be64(x) __builtin_bswap64(x) 61 | # define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x) 62 | # define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x) 63 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 64 | # define __bpf_ntohs(x) (x) 65 | # define __bpf_htons(x) (x) 66 | # define __bpf_constant_ntohs(x) (x) 67 | # define __bpf_constant_htons(x) (x) 68 | # define __bpf_ntohl(x) (x) 69 | # define __bpf_htonl(x) (x) 70 | # define __bpf_constant_ntohl(x) (x) 71 | # define __bpf_constant_htonl(x) (x) 72 | # define __bpf_be64_to_cpu(x) (x) 73 | # define __bpf_cpu_to_be64(x) (x) 74 | # define __bpf_constant_be64_to_cpu(x) (x) 75 | # define __bpf_constant_cpu_to_be64(x) (x) 76 | #else 77 | # error "Fix your compiler's __BYTE_ORDER__?!" 78 | #endif 79 | 80 | #define bpf_htons(x) \ 81 | (__builtin_constant_p(x) ? \ 82 | __bpf_constant_htons(x) : __bpf_htons(x)) 83 | #define bpf_ntohs(x) \ 84 | (__builtin_constant_p(x) ? \ 85 | __bpf_constant_ntohs(x) : __bpf_ntohs(x)) 86 | #define bpf_htonl(x) \ 87 | (__builtin_constant_p(x) ? \ 88 | __bpf_constant_htonl(x) : __bpf_htonl(x)) 89 | #define bpf_ntohl(x) \ 90 | (__builtin_constant_p(x) ? \ 91 | __bpf_constant_ntohl(x) : __bpf_ntohl(x)) 92 | #define bpf_cpu_to_be64(x) \ 93 | (__builtin_constant_p(x) ? \ 94 | __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) 95 | #define bpf_be64_to_cpu(x) \ 96 | (__builtin_constant_p(x) ? \ 97 | __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) 98 | 99 | #endif /* __BPF_ENDIAN__ */ 100 | -------------------------------------------------------------------------------- /bpf/headers/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __BPF_HELPERS__ 3 | #define __BPF_HELPERS__ 4 | 5 | /* 6 | * Note that bpf programs need to include either 7 | * vmlinux.h (auto-generated from BTF) or linux/types.h 8 | * in advance since bpf_helper_defs.h uses such types 9 | * as __u64. 10 | */ 11 | #include "bpf_helper_defs.h" 12 | 13 | #define __uint(name, val) int (*name)[val] 14 | #define __type(name, val) typeof(val) *name 15 | #define __array(name, val) typeof(val) *name[] 16 | 17 | /* 18 | * Helper macro to place programs, maps, license in 19 | * different sections in elf_bpf file. Section names 20 | * are interpreted by libbpf depending on the context (BPF programs, BPF maps, 21 | * extern variables, etc). 22 | * To allow use of SEC() with externs (e.g., for extern .maps declarations), 23 | * make sure __attribute__((unused)) doesn't trigger compilation warning. 24 | */ 25 | #if __GNUC__ && !__clang__ 26 | 27 | /* 28 | * Pragma macros are broken on GCC 29 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 30 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90400 31 | */ 32 | #define SEC(name) __attribute__((section(name), used)) 33 | 34 | #else 35 | 36 | #define SEC(name) \ 37 | _Pragma("GCC diagnostic push") \ 38 | _Pragma("GCC diagnostic ignored \"-Wignored-attributes\"") \ 39 | __attribute__((section(name), used)) \ 40 | _Pragma("GCC diagnostic pop") \ 41 | 42 | #endif 43 | 44 | /* Avoid 'linux/stddef.h' definition of '__always_inline'. */ 45 | #undef __always_inline 46 | #define __always_inline inline __attribute__((always_inline)) 47 | 48 | #ifndef __noinline 49 | #define __noinline __attribute__((noinline)) 50 | #endif 51 | #ifndef __weak 52 | #define __weak __attribute__((weak)) 53 | #endif 54 | 55 | /* 56 | * Use __hidden attribute to mark a non-static BPF subprogram effectively 57 | * static for BPF verifier's verification algorithm purposes, allowing more 58 | * extensive and permissive BPF verification process, taking into account 59 | * subprogram's caller context. 60 | */ 61 | #define __hidden __attribute__((visibility("hidden"))) 62 | 63 | /* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include 64 | * any system-level headers (such as stddef.h, linux/version.h, etc), and 65 | * commonly-used macros like NULL and KERNEL_VERSION aren't available through 66 | * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define 67 | * them on their own. So as a convenience, provide such definitions here. 68 | */ 69 | #ifndef NULL 70 | #define NULL ((void *)0) 71 | #endif 72 | 73 | #ifndef KERNEL_VERSION 74 | #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) 75 | #endif 76 | 77 | /* 78 | * Helper macros to manipulate data structures 79 | */ 80 | 81 | /* offsetof() definition that uses __builtin_offset() might not preserve field 82 | * offset CO-RE relocation properly, so force-redefine offsetof() using 83 | * old-school approach which works with CO-RE correctly 84 | */ 85 | #undef offsetof 86 | #define offsetof(type, member) ((unsigned long)&((type *)0)->member) 87 | 88 | /* redefined container_of() to ensure we use the above offsetof() macro */ 89 | #undef container_of 90 | #define container_of(ptr, type, member) \ 91 | ({ \ 92 | void *__mptr = (void *)(ptr); \ 93 | ((type *)(__mptr - offsetof(type, member))); \ 94 | }) 95 | 96 | /* 97 | * Compiler (optimization) barrier. 98 | */ 99 | #ifndef barrier 100 | #define barrier() asm volatile("" ::: "memory") 101 | #endif 102 | 103 | /* Variable-specific compiler (optimization) barrier. It's a no-op which makes 104 | * compiler believe that there is some black box modification of a given 105 | * variable and thus prevents compiler from making extra assumption about its 106 | * value and potential simplifications and optimizations on this variable. 107 | * 108 | * E.g., compiler might often delay or even omit 32-bit to 64-bit casting of 109 | * a variable, making some code patterns unverifiable. Putting barrier_var() 110 | * in place will ensure that cast is performed before the barrier_var() 111 | * invocation, because compiler has to pessimistically assume that embedded 112 | * asm section might perform some extra operations on that variable. 113 | * 114 | * This is a variable-specific variant of more global barrier(). 115 | */ 116 | #ifndef barrier_var 117 | #define barrier_var(var) asm volatile("" : "+r"(var)) 118 | #endif 119 | 120 | /* 121 | * Helper macro to throw a compilation error if __bpf_unreachable() gets 122 | * built into the resulting code. This works given BPF back end does not 123 | * implement __builtin_trap(). This is useful to assert that certain paths 124 | * of the program code are never used and hence eliminated by the compiler. 125 | * 126 | * For example, consider a switch statement that covers known cases used by 127 | * the program. __bpf_unreachable() can then reside in the default case. If 128 | * the program gets extended such that a case is not covered in the switch 129 | * statement, then it will throw a build error due to the default case not 130 | * being compiled out. 131 | */ 132 | #ifndef __bpf_unreachable 133 | # define __bpf_unreachable() __builtin_trap() 134 | #endif 135 | 136 | /* 137 | * Helper function to perform a tail call with a constant/immediate map slot. 138 | */ 139 | #if __clang_major__ >= 8 && defined(__bpf__) 140 | static __always_inline void 141 | bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) 142 | { 143 | if (!__builtin_constant_p(slot)) 144 | __bpf_unreachable(); 145 | 146 | /* 147 | * Provide a hard guarantee that LLVM won't optimize setting r2 (map 148 | * pointer) and r3 (constant map index) from _different paths_ ending 149 | * up at the _same_ call insn as otherwise we won't be able to use the 150 | * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel 151 | * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key 152 | * tracking for prog array pokes") for details on verifier tracking. 153 | * 154 | * Note on clobber list: we need to stay in-line with BPF calling 155 | * convention, so even if we don't end up using r0, r4, r5, we need 156 | * to mark them as clobber so that LLVM doesn't end up using them 157 | * before / after the call. 158 | */ 159 | asm volatile("r1 = %[ctx]\n\t" 160 | "r2 = %[map]\n\t" 161 | "r3 = %[slot]\n\t" 162 | "call 12" 163 | :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot) 164 | : "r0", "r1", "r2", "r3", "r4", "r5"); 165 | } 166 | #endif 167 | 168 | enum libbpf_pin_type { 169 | LIBBPF_PIN_NONE, 170 | /* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */ 171 | LIBBPF_PIN_BY_NAME, 172 | }; 173 | 174 | enum libbpf_tristate { 175 | TRI_NO = 0, 176 | TRI_YES = 1, 177 | TRI_MODULE = 2, 178 | }; 179 | 180 | #define __kconfig __attribute__((section(".kconfig"))) 181 | #define __ksym __attribute__((section(".ksyms"))) 182 | #define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted"))) 183 | #define __kptr __attribute__((btf_type_tag("kptr"))) 184 | #define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr"))) 185 | 186 | #define bpf_ksym_exists(sym) ({ \ 187 | _Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \ 188 | !!sym; \ 189 | }) 190 | 191 | #ifndef ___bpf_concat 192 | #define ___bpf_concat(a, b) a ## b 193 | #endif 194 | #ifndef ___bpf_apply 195 | #define ___bpf_apply(fn, n) ___bpf_concat(fn, n) 196 | #endif 197 | #ifndef ___bpf_nth 198 | #define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N 199 | #endif 200 | #ifndef ___bpf_narg 201 | #define ___bpf_narg(...) \ 202 | ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 203 | #endif 204 | 205 | #define ___bpf_fill0(arr, p, x) do {} while (0) 206 | #define ___bpf_fill1(arr, p, x) arr[p] = x 207 | #define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args) 208 | #define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args) 209 | #define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args) 210 | #define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args) 211 | #define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args) 212 | #define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args) 213 | #define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args) 214 | #define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args) 215 | #define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args) 216 | #define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args) 217 | #define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args) 218 | #define ___bpf_fill(arr, args...) \ 219 | ___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args) 220 | 221 | /* 222 | * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values 223 | * in a structure. 224 | */ 225 | #define BPF_SEQ_PRINTF(seq, fmt, args...) \ 226 | ({ \ 227 | static const char ___fmt[] = fmt; \ 228 | unsigned long long ___param[___bpf_narg(args)]; \ 229 | \ 230 | _Pragma("GCC diagnostic push") \ 231 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 232 | ___bpf_fill(___param, args); \ 233 | _Pragma("GCC diagnostic pop") \ 234 | \ 235 | bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \ 236 | ___param, sizeof(___param)); \ 237 | }) 238 | 239 | /* 240 | * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of 241 | * an array of u64. 242 | */ 243 | #define BPF_SNPRINTF(out, out_size, fmt, args...) \ 244 | ({ \ 245 | static const char ___fmt[] = fmt; \ 246 | unsigned long long ___param[___bpf_narg(args)]; \ 247 | \ 248 | _Pragma("GCC diagnostic push") \ 249 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 250 | ___bpf_fill(___param, args); \ 251 | _Pragma("GCC diagnostic pop") \ 252 | \ 253 | bpf_snprintf(out, out_size, ___fmt, \ 254 | ___param, sizeof(___param)); \ 255 | }) 256 | 257 | #ifdef BPF_NO_GLOBAL_DATA 258 | #define BPF_PRINTK_FMT_MOD 259 | #else 260 | #define BPF_PRINTK_FMT_MOD static const 261 | #endif 262 | 263 | #define __bpf_printk(fmt, ...) \ 264 | ({ \ 265 | BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \ 266 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 267 | ##__VA_ARGS__); \ 268 | }) 269 | 270 | /* 271 | * __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments 272 | * instead of an array of u64. 273 | */ 274 | #define __bpf_vprintk(fmt, args...) \ 275 | ({ \ 276 | static const char ___fmt[] = fmt; \ 277 | unsigned long long ___param[___bpf_narg(args)]; \ 278 | \ 279 | _Pragma("GCC diagnostic push") \ 280 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 281 | ___bpf_fill(___param, args); \ 282 | _Pragma("GCC diagnostic pop") \ 283 | \ 284 | bpf_trace_vprintk(___fmt, sizeof(___fmt), \ 285 | ___param, sizeof(___param)); \ 286 | }) 287 | 288 | /* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args 289 | * Otherwise use __bpf_vprintk 290 | */ 291 | #define ___bpf_pick_printk(...) \ 292 | ___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ 293 | __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \ 294 | __bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\ 295 | __bpf_printk /*1*/, __bpf_printk /*0*/) 296 | 297 | /* Helper macro to print out debug messages */ 298 | #define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args) 299 | 300 | struct bpf_iter_num; 301 | 302 | extern int bpf_iter_num_new(struct bpf_iter_num *it, int start, int end) __weak __ksym; 303 | extern int *bpf_iter_num_next(struct bpf_iter_num *it) __weak __ksym; 304 | extern void bpf_iter_num_destroy(struct bpf_iter_num *it) __weak __ksym; 305 | 306 | #ifndef bpf_for_each 307 | /* bpf_for_each(iter_type, cur_elem, args...) provides generic construct for 308 | * using BPF open-coded iterators without having to write mundane explicit 309 | * low-level loop logic. Instead, it provides for()-like generic construct 310 | * that can be used pretty naturally. E.g., for some hypothetical cgroup 311 | * iterator, you'd write: 312 | * 313 | * struct cgroup *cg, *parent_cg = <...>; 314 | * 315 | * bpf_for_each(cgroup, cg, parent_cg, CG_ITER_CHILDREN) { 316 | * bpf_printk("Child cgroup id = %d", cg->cgroup_id); 317 | * if (cg->cgroup_id == 123) 318 | * break; 319 | * } 320 | * 321 | * I.e., it looks almost like high-level for each loop in other languages, 322 | * supports continue/break, and is verifiable by BPF verifier. 323 | * 324 | * For iterating integers, the difference betwen bpf_for_each(num, i, N, M) 325 | * and bpf_for(i, N, M) is in that bpf_for() provides additional proof to 326 | * verifier that i is in [N, M) range, and in bpf_for_each() case i is `int 327 | * *`, not just `int`. So for integers bpf_for() is more convenient. 328 | * 329 | * Note: this macro relies on C99 feature of allowing to declare variables 330 | * inside for() loop, bound to for() loop lifetime. It also utilizes GCC 331 | * extension: __attribute__((cleanup())), supported by both GCC and 332 | * Clang. 333 | */ 334 | #define bpf_for_each(type, cur, args...) for ( \ 335 | /* initialize and define destructor */ \ 336 | struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */, \ 337 | cleanup(bpf_iter_##type##_destroy))), \ 338 | /* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */ \ 339 | *___p __attribute__((unused)) = ( \ 340 | bpf_iter_##type##_new(&___it, ##args), \ 341 | /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ 342 | /* for bpf_iter_##type##_destroy() when used from cleanup() attribute */ \ 343 | (void)bpf_iter_##type##_destroy, (void *)0); \ 344 | /* iteration and termination check */ \ 345 | (((cur) = bpf_iter_##type##_next(&___it))); \ 346 | ) 347 | #endif /* bpf_for_each */ 348 | 349 | #ifndef bpf_for 350 | /* bpf_for(i, start, end) implements a for()-like looping construct that sets 351 | * provided integer variable *i* to values starting from *start* through, 352 | * but not including, *end*. It also proves to BPF verifier that *i* belongs 353 | * to range [start, end), so this can be used for accessing arrays without 354 | * extra checks. 355 | * 356 | * Note: *start* and *end* are assumed to be expressions with no side effects 357 | * and whose values do not change throughout bpf_for() loop execution. They do 358 | * not have to be statically known or constant, though. 359 | * 360 | * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for() 361 | * loop bound variables and cleanup attribute, supported by GCC and Clang. 362 | */ 363 | #define bpf_for(i, start, end) for ( \ 364 | /* initialize and define destructor */ \ 365 | struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \ 366 | cleanup(bpf_iter_num_destroy))), \ 367 | /* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \ 368 | *___p __attribute__((unused)) = ( \ 369 | bpf_iter_num_new(&___it, (start), (end)), \ 370 | /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ 371 | /* for bpf_iter_num_destroy() when used from cleanup() attribute */ \ 372 | (void)bpf_iter_num_destroy, (void *)0); \ 373 | ({ \ 374 | /* iteration step */ \ 375 | int *___t = bpf_iter_num_next(&___it); \ 376 | /* termination and bounds check */ \ 377 | (___t && ((i) = *___t, (i) >= (start) && (i) < (end))); \ 378 | }); \ 379 | ) 380 | #endif /* bpf_for */ 381 | 382 | #ifndef bpf_repeat 383 | /* bpf_repeat(N) performs N iterations without exposing iteration number 384 | * 385 | * Note: similarly to bpf_for_each(), it relies on C99 feature of declaring for() 386 | * loop bound variables and cleanup attribute, supported by GCC and Clang. 387 | */ 388 | #define bpf_repeat(N) for ( \ 389 | /* initialize and define destructor */ \ 390 | struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \ 391 | cleanup(bpf_iter_num_destroy))), \ 392 | /* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \ 393 | *___p __attribute__((unused)) = ( \ 394 | bpf_iter_num_new(&___it, 0, (N)), \ 395 | /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ 396 | /* for bpf_iter_num_destroy() when used from cleanup() attribute */ \ 397 | (void)bpf_iter_num_destroy, (void *)0); \ 398 | bpf_iter_num_next(&___it); \ 399 | /* nothing here */ \ 400 | ) 401 | #endif /* bpf_repeat */ 402 | 403 | #endif 404 | -------------------------------------------------------------------------------- /bpf/headers/bpf_probe_read.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | 3 | #ifndef __BPF_PROBE_READ_H__ 4 | #define __BPF_PROBE_READ_H__ 5 | 6 | #define ___concat(a, b) a##b 7 | #define ___apply(fn, n) ___concat(fn, n) 8 | #define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N 9 | 10 | /* 11 | * return number of provided arguments; used for switch-based variadic macro 12 | * definitions (see ___last, ___arrow, etc below) 13 | */ 14 | #define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 15 | /* 16 | * return 0 if no arguments are passed, N - otherwise; used for 17 | * recursively-defined macros to specify termination (0) case, and generic 18 | * (N) case (e.g., ___read_ptrs, ___core_read) 19 | */ 20 | #define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0) 21 | 22 | #define ___last1(x) x 23 | #define ___last2(a, x) x 24 | #define ___last3(a, b, x) x 25 | #define ___last4(a, b, c, x) x 26 | #define ___last5(a, b, c, d, x) x 27 | #define ___last6(a, b, c, d, e, x) x 28 | #define ___last7(a, b, c, d, e, f, x) x 29 | #define ___last8(a, b, c, d, e, f, g, x) x 30 | #define ___last9(a, b, c, d, e, f, g, h, x) x 31 | #define ___last10(a, b, c, d, e, f, g, h, i, x) x 32 | #define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__) 33 | 34 | #define ___nolast2(a, _) a 35 | #define ___nolast3(a, b, _) a, b 36 | #define ___nolast4(a, b, c, _) a, b, c 37 | #define ___nolast5(a, b, c, d, _) a, b, c, d 38 | #define ___nolast6(a, b, c, d, e, _) a, b, c, d, e 39 | #define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f 40 | #define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g 41 | #define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h 42 | #define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i 43 | #define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__) 44 | 45 | #define ___arrow1(a) a 46 | #define ___arrow2(a, b) a->b 47 | #define ___arrow3(a, b, c) a->b->c 48 | #define ___arrow4(a, b, c, d) a->b->c->d 49 | #define ___arrow5(a, b, c, d, e) a->b->c->d->e 50 | #define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f 51 | #define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g 52 | #define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h 53 | #define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i 54 | #define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j 55 | #define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__) 56 | 57 | #define ___type(...) typeof(___arrow(__VA_ARGS__)) 58 | 59 | #define ___read(read_fn, dst, src_type, src, accessor) \ 60 | read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor) 61 | 62 | /* "recursively" read a sequence of inner pointers using local __t var */ 63 | #define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a); 64 | #define ___rd_last(fn, ...) \ 65 | ___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__)); 66 | #define ___rd_p1(fn, ...) \ 67 | const void *__t; \ 68 | ___rd_first(fn, __VA_ARGS__) 69 | #define ___rd_p2(fn, ...) \ 70 | ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 71 | #define ___rd_p3(fn, ...) \ 72 | ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 73 | #define ___rd_p4(fn, ...) \ 74 | ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 75 | #define ___rd_p5(fn, ...) \ 76 | ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 77 | #define ___rd_p6(fn, ...) \ 78 | ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 79 | #define ___rd_p7(fn, ...) \ 80 | ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 81 | #define ___rd_p8(fn, ...) \ 82 | ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 83 | #define ___rd_p9(fn, ...) \ 84 | ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__) 85 | #define ___read_ptrs(fn, src, ...) \ 86 | ___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__) 87 | 88 | #define ___core_read0(fn, fn_ptr, dst, src, a) \ 89 | ___read(fn, dst, ___type(src), src, a); 90 | #define ___core_readN(fn, fn_ptr, dst, src, ...) \ 91 | ___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__)) \ 92 | ___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \ 93 | ___last(__VA_ARGS__)); 94 | #define ___core_read(fn, fn_ptr, dst, src, a, ...) \ 95 | ___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst, src, a, \ 96 | ##__VA_ARGS__) 97 | 98 | #define BPF_PROBE_READ_KERNEL_INTO(dst, src, a, ...) \ 99 | ({___core_read(bpf_probe_read_kernel, bpf_probe_read_kernel, dst, (src), a, \ 100 | ##__VA_ARGS__)}) 101 | 102 | #define BPF_PROBE_READ_KERNEL(src, a, ...) \ 103 | ({ \ 104 | ___type((src), a, ##__VA_ARGS__) __r; \ 105 | BPF_PROBE_READ_KERNEL_INTO(&__r, (src), a, ##__VA_ARGS__); \ 106 | __r; \ 107 | }) 108 | 109 | #endif // __BPF_PROBE_READ_H__ -------------------------------------------------------------------------------- /bpf/headers/bpf_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __BPF_TIMER_H__ 2 | #define __BPF_TIMER_H__ 3 | 4 | #include "vmlinux.h" 5 | 6 | #define CLOCK_MONOTONIC 1 7 | #define CLOCK_BOOTTIME 2 8 | struct bpf_timer { 9 | __u64 __opaque[2]; 10 | } __attribute__((aligned(8))); 11 | 12 | struct bpf_dynptr { 13 | __u64 __opaque[2]; 14 | } __attribute__((aligned(8))); 15 | 16 | struct bpf_list_head { 17 | __u64 __opaque[2]; 18 | } __attribute__((aligned(8))); 19 | 20 | struct bpf_list_node { 21 | __u64 __opaque[3]; 22 | } __attribute__((aligned(8))); 23 | 24 | struct bpf_rb_root { 25 | __u64 __opaque[2]; 26 | } __attribute__((aligned(8))); 27 | 28 | struct bpf_rb_node { 29 | __u64 __opaque[4]; 30 | } __attribute__((aligned(8))); 31 | 32 | struct bpf_refcount { 33 | __u32 __opaque[1]; 34 | } __attribute__((aligned(4))); 35 | 36 | struct bpf_iter_num { 37 | __u64 __opaque[1]; 38 | } __attribute__((aligned(8))); 39 | 40 | #endif -------------------------------------------------------------------------------- /bpf/headers/bpf_tracing.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __BPF_TRACING_H__ 3 | #define __BPF_TRACING_H__ 4 | 5 | #include "bpf_helpers.h" 6 | 7 | /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ 8 | #if defined(__TARGET_ARCH_x86) 9 | #define bpf_target_x86 10 | #define bpf_target_defined 11 | #elif defined(__TARGET_ARCH_s390) 12 | #define bpf_target_s390 13 | #define bpf_target_defined 14 | #elif defined(__TARGET_ARCH_arm) 15 | #define bpf_target_arm 16 | #define bpf_target_defined 17 | #elif defined(__TARGET_ARCH_arm64) 18 | #define bpf_target_arm64 19 | #define bpf_target_defined 20 | #elif defined(__TARGET_ARCH_mips) 21 | #define bpf_target_mips 22 | #define bpf_target_defined 23 | #elif defined(__TARGET_ARCH_powerpc) 24 | #define bpf_target_powerpc 25 | #define bpf_target_defined 26 | #elif defined(__TARGET_ARCH_sparc) 27 | #define bpf_target_sparc 28 | #define bpf_target_defined 29 | #elif defined(__TARGET_ARCH_riscv) 30 | #define bpf_target_riscv 31 | #define bpf_target_defined 32 | #elif defined(__TARGET_ARCH_arc) 33 | #define bpf_target_arc 34 | #define bpf_target_defined 35 | #elif defined(__TARGET_ARCH_loongarch) 36 | #define bpf_target_loongarch 37 | #define bpf_target_defined 38 | #else 39 | 40 | /* Fall back to what the compiler says */ 41 | #if defined(__x86_64__) 42 | #define bpf_target_x86 43 | #define bpf_target_defined 44 | #elif defined(__s390__) 45 | #define bpf_target_s390 46 | #define bpf_target_defined 47 | #elif defined(__arm__) 48 | #define bpf_target_arm 49 | #define bpf_target_defined 50 | #elif defined(__aarch64__) 51 | #define bpf_target_arm64 52 | #define bpf_target_defined 53 | #elif defined(__mips__) 54 | #define bpf_target_mips 55 | #define bpf_target_defined 56 | #elif defined(__powerpc__) 57 | #define bpf_target_powerpc 58 | #define bpf_target_defined 59 | #elif defined(__sparc__) 60 | #define bpf_target_sparc 61 | #define bpf_target_defined 62 | #elif defined(__riscv) && __riscv_xlen == 64 63 | #define bpf_target_riscv 64 | #define bpf_target_defined 65 | #elif defined(__arc__) 66 | #define bpf_target_arc 67 | #define bpf_target_defined 68 | #elif defined(__loongarch__) 69 | #define bpf_target_loongarch 70 | #define bpf_target_defined 71 | #endif /* no compiler target */ 72 | 73 | #endif 74 | 75 | #ifndef __BPF_TARGET_MISSING 76 | #define __BPF_TARGET_MISSING "GCC error \"Must specify a BPF target arch via __TARGET_ARCH_xxx\"" 77 | #endif 78 | 79 | #if defined(bpf_target_x86) 80 | 81 | /* 82 | * https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI 83 | */ 84 | 85 | #if defined(__KERNEL__) || defined(__VMLINUX_H__) 86 | 87 | #define __PT_PARM1_REG di 88 | #define __PT_PARM2_REG si 89 | #define __PT_PARM3_REG dx 90 | #define __PT_PARM4_REG cx 91 | #define __PT_PARM5_REG r8 92 | #define __PT_PARM6_REG r9 93 | /* 94 | * Syscall uses r10 for PARM4. See arch/x86/entry/entry_64.S:entry_SYSCALL_64 95 | * comments in Linux sources. And refer to syscall(2) manpage. 96 | */ 97 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 98 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 99 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 100 | #define __PT_PARM4_SYSCALL_REG r10 101 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 102 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 103 | 104 | #define __PT_RET_REG sp 105 | #define __PT_FP_REG bp 106 | #define __PT_RC_REG ax 107 | #define __PT_SP_REG sp 108 | #define __PT_IP_REG ip 109 | 110 | #else 111 | 112 | #ifdef __i386__ 113 | 114 | /* i386 kernel is built with -mregparm=3 */ 115 | #define __PT_PARM1_REG eax 116 | #define __PT_PARM2_REG edx 117 | #define __PT_PARM3_REG ecx 118 | /* i386 syscall ABI is very different, refer to syscall(2) manpage */ 119 | #define __PT_PARM1_SYSCALL_REG ebx 120 | #define __PT_PARM2_SYSCALL_REG ecx 121 | #define __PT_PARM3_SYSCALL_REG edx 122 | #define __PT_PARM4_SYSCALL_REG esi 123 | #define __PT_PARM5_SYSCALL_REG edi 124 | #define __PT_PARM6_SYSCALL_REG ebp 125 | 126 | #define __PT_RET_REG esp 127 | #define __PT_FP_REG ebp 128 | #define __PT_RC_REG eax 129 | #define __PT_SP_REG esp 130 | #define __PT_IP_REG eip 131 | 132 | #else /* __i386__ */ 133 | 134 | #define __PT_PARM1_REG rdi 135 | #define __PT_PARM2_REG rsi 136 | #define __PT_PARM3_REG rdx 137 | #define __PT_PARM4_REG rcx 138 | #define __PT_PARM5_REG r8 139 | #define __PT_PARM6_REG r9 140 | 141 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 142 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 143 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 144 | #define __PT_PARM4_SYSCALL_REG r10 145 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 146 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 147 | 148 | #define __PT_RET_REG rsp 149 | #define __PT_FP_REG rbp 150 | #define __PT_RC_REG rax 151 | #define __PT_SP_REG rsp 152 | #define __PT_IP_REG rip 153 | 154 | #endif /* __i386__ */ 155 | 156 | #endif /* __KERNEL__ || __VMLINUX_H__ */ 157 | 158 | #elif defined(bpf_target_s390) 159 | 160 | /* 161 | * https://github.com/IBM/s390x-abi/releases/download/v1.6/lzsabi_s390x.pdf 162 | */ 163 | 164 | struct pt_regs___s390 { 165 | unsigned long orig_gpr2; 166 | }; 167 | 168 | /* s390 provides user_pt_regs instead of struct pt_regs to userspace */ 169 | #define __PT_REGS_CAST(x) ((const user_pt_regs *)(x)) 170 | #define __PT_PARM1_REG gprs[2] 171 | #define __PT_PARM2_REG gprs[3] 172 | #define __PT_PARM3_REG gprs[4] 173 | #define __PT_PARM4_REG gprs[5] 174 | #define __PT_PARM5_REG gprs[6] 175 | 176 | #define __PT_PARM1_SYSCALL_REG orig_gpr2 177 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 178 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 179 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 180 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 181 | #define __PT_PARM6_SYSCALL_REG gprs[7] 182 | #define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x) 183 | #define PT_REGS_PARM1_CORE_SYSCALL(x) \ 184 | BPF_CORE_READ((const struct pt_regs___s390 *)(x), __PT_PARM1_SYSCALL_REG) 185 | 186 | #define __PT_RET_REG gprs[14] 187 | #define __PT_FP_REG gprs[11] /* Works only with CONFIG_FRAME_POINTER */ 188 | #define __PT_RC_REG gprs[2] 189 | #define __PT_SP_REG gprs[15] 190 | #define __PT_IP_REG psw.addr 191 | 192 | #elif defined(bpf_target_arm) 193 | 194 | /* 195 | * https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers 196 | */ 197 | 198 | #define __PT_PARM1_REG uregs[0] 199 | #define __PT_PARM2_REG uregs[1] 200 | #define __PT_PARM3_REG uregs[2] 201 | #define __PT_PARM4_REG uregs[3] 202 | 203 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 204 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 205 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 206 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 207 | #define __PT_PARM5_SYSCALL_REG uregs[4] 208 | #define __PT_PARM6_SYSCALL_REG uregs[5] 209 | #define __PT_PARM7_SYSCALL_REG uregs[6] 210 | 211 | #define __PT_RET_REG uregs[14] 212 | #define __PT_FP_REG uregs[11] /* Works only with CONFIG_FRAME_POINTER */ 213 | #define __PT_RC_REG uregs[0] 214 | #define __PT_SP_REG uregs[13] 215 | #define __PT_IP_REG uregs[12] 216 | 217 | #elif defined(bpf_target_arm64) 218 | 219 | /* 220 | * https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers 221 | */ 222 | 223 | struct pt_regs___arm64 { 224 | unsigned long orig_x0; 225 | }; 226 | 227 | /* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ 228 | #define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x)) 229 | #define __PT_PARM1_REG regs[0] 230 | #define __PT_PARM2_REG regs[1] 231 | #define __PT_PARM3_REG regs[2] 232 | #define __PT_PARM4_REG regs[3] 233 | #define __PT_PARM5_REG regs[4] 234 | #define __PT_PARM6_REG regs[5] 235 | #define __PT_PARM7_REG regs[6] 236 | #define __PT_PARM8_REG regs[7] 237 | 238 | #define __PT_PARM1_SYSCALL_REG orig_x0 239 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 240 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 241 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 242 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 243 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 244 | #define PT_REGS_PARM1_SYSCALL(x) PT_REGS_PARM1_CORE_SYSCALL(x) 245 | #define PT_REGS_PARM1_CORE_SYSCALL(x) \ 246 | BPF_CORE_READ((const struct pt_regs___arm64 *)(x), __PT_PARM1_SYSCALL_REG) 247 | 248 | #define __PT_RET_REG regs[30] 249 | #define __PT_FP_REG regs[29] /* Works only with CONFIG_FRAME_POINTER */ 250 | #define __PT_RC_REG regs[0] 251 | #define __PT_SP_REG sp 252 | #define __PT_IP_REG pc 253 | 254 | #elif defined(bpf_target_mips) 255 | 256 | /* 257 | * N64 ABI is assumed right now. 258 | * https://en.wikipedia.org/wiki/MIPS_architecture#Calling_conventions 259 | */ 260 | 261 | #define __PT_PARM1_REG regs[4] 262 | #define __PT_PARM2_REG regs[5] 263 | #define __PT_PARM3_REG regs[6] 264 | #define __PT_PARM4_REG regs[7] 265 | #define __PT_PARM5_REG regs[8] 266 | #define __PT_PARM6_REG regs[9] 267 | #define __PT_PARM7_REG regs[10] 268 | #define __PT_PARM8_REG regs[11] 269 | 270 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 271 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 272 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 273 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 274 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG /* only N32/N64 */ 275 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG /* only N32/N64 */ 276 | 277 | #define __PT_RET_REG regs[31] 278 | #define __PT_FP_REG regs[30] /* Works only with CONFIG_FRAME_POINTER */ 279 | #define __PT_RC_REG regs[2] 280 | #define __PT_SP_REG regs[29] 281 | #define __PT_IP_REG cp0_epc 282 | 283 | #elif defined(bpf_target_powerpc) 284 | 285 | /* 286 | * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf (page 3-14, 287 | * section "Function Calling Sequence") 288 | */ 289 | 290 | #define __PT_PARM1_REG gpr[3] 291 | #define __PT_PARM2_REG gpr[4] 292 | #define __PT_PARM3_REG gpr[5] 293 | #define __PT_PARM4_REG gpr[6] 294 | #define __PT_PARM5_REG gpr[7] 295 | #define __PT_PARM6_REG gpr[8] 296 | #define __PT_PARM7_REG gpr[9] 297 | #define __PT_PARM8_REG gpr[10] 298 | 299 | /* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER. */ 300 | #define PT_REGS_SYSCALL_REGS(ctx) ctx 301 | #define __PT_PARM1_SYSCALL_REG orig_gpr3 302 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 303 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 304 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 305 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 306 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 307 | #if !defined(__arch64__) 308 | #define __PT_PARM7_SYSCALL_REG __PT_PARM7_REG /* only powerpc (not powerpc64) */ 309 | #endif 310 | 311 | #define __PT_RET_REG regs[31] 312 | #define __PT_FP_REG __unsupported__ 313 | #define __PT_RC_REG gpr[3] 314 | #define __PT_SP_REG sp 315 | #define __PT_IP_REG nip 316 | 317 | #elif defined(bpf_target_sparc) 318 | 319 | /* 320 | * https://en.wikipedia.org/wiki/Calling_convention#SPARC 321 | */ 322 | 323 | #define __PT_PARM1_REG u_regs[UREG_I0] 324 | #define __PT_PARM2_REG u_regs[UREG_I1] 325 | #define __PT_PARM3_REG u_regs[UREG_I2] 326 | #define __PT_PARM4_REG u_regs[UREG_I3] 327 | #define __PT_PARM5_REG u_regs[UREG_I4] 328 | #define __PT_PARM6_REG u_regs[UREG_I5] 329 | 330 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 331 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 332 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 333 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 334 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 335 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 336 | 337 | #define __PT_RET_REG u_regs[UREG_I7] 338 | #define __PT_FP_REG __unsupported__ 339 | #define __PT_RC_REG u_regs[UREG_I0] 340 | #define __PT_SP_REG u_regs[UREG_FP] 341 | /* Should this also be a bpf_target check for the sparc case? */ 342 | #if defined(__arch64__) 343 | #define __PT_IP_REG tpc 344 | #else 345 | #define __PT_IP_REG pc 346 | #endif 347 | 348 | #elif defined(bpf_target_riscv) 349 | 350 | /* 351 | * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions 352 | */ 353 | 354 | /* riscv provides struct user_regs_struct instead of struct pt_regs to userspace */ 355 | #define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x)) 356 | #define __PT_PARM1_REG a0 357 | #define __PT_PARM2_REG a1 358 | #define __PT_PARM3_REG a2 359 | #define __PT_PARM4_REG a3 360 | #define __PT_PARM5_REG a4 361 | #define __PT_PARM6_REG a5 362 | #define __PT_PARM7_REG a6 363 | #define __PT_PARM8_REG a7 364 | 365 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 366 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 367 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 368 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 369 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 370 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 371 | 372 | #define __PT_RET_REG ra 373 | #define __PT_FP_REG s0 374 | #define __PT_RC_REG a0 375 | #define __PT_SP_REG sp 376 | #define __PT_IP_REG pc 377 | 378 | #elif defined(bpf_target_arc) 379 | 380 | /* 381 | * Section "Function Calling Sequence" (page 24): 382 | * https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf 383 | */ 384 | 385 | /* arc provides struct user_regs_struct instead of struct pt_regs to userspace */ 386 | #define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x)) 387 | #define __PT_PARM1_REG scratch.r0 388 | #define __PT_PARM2_REG scratch.r1 389 | #define __PT_PARM3_REG scratch.r2 390 | #define __PT_PARM4_REG scratch.r3 391 | #define __PT_PARM5_REG scratch.r4 392 | #define __PT_PARM6_REG scratch.r5 393 | #define __PT_PARM7_REG scratch.r6 394 | #define __PT_PARM8_REG scratch.r7 395 | 396 | /* arc does not select ARCH_HAS_SYSCALL_WRAPPER. */ 397 | #define PT_REGS_SYSCALL_REGS(ctx) ctx 398 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 399 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 400 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 401 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 402 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 403 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 404 | 405 | #define __PT_RET_REG scratch.blink 406 | #define __PT_FP_REG scratch.fp 407 | #define __PT_RC_REG scratch.r0 408 | #define __PT_SP_REG scratch.sp 409 | #define __PT_IP_REG scratch.ret 410 | 411 | #elif defined(bpf_target_loongarch) 412 | 413 | /* 414 | * https://docs.kernel.org/loongarch/introduction.html 415 | * https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html 416 | */ 417 | 418 | /* loongarch provides struct user_pt_regs instead of struct pt_regs to userspace */ 419 | #define __PT_REGS_CAST(x) ((const struct user_pt_regs *)(x)) 420 | #define __PT_PARM1_REG regs[4] 421 | #define __PT_PARM2_REG regs[5] 422 | #define __PT_PARM3_REG regs[6] 423 | #define __PT_PARM4_REG regs[7] 424 | #define __PT_PARM5_REG regs[8] 425 | #define __PT_PARM6_REG regs[9] 426 | #define __PT_PARM7_REG regs[10] 427 | #define __PT_PARM8_REG regs[11] 428 | 429 | /* loongarch does not select ARCH_HAS_SYSCALL_WRAPPER. */ 430 | #define PT_REGS_SYSCALL_REGS(ctx) ctx 431 | #define __PT_PARM1_SYSCALL_REG __PT_PARM1_REG 432 | #define __PT_PARM2_SYSCALL_REG __PT_PARM2_REG 433 | #define __PT_PARM3_SYSCALL_REG __PT_PARM3_REG 434 | #define __PT_PARM4_SYSCALL_REG __PT_PARM4_REG 435 | #define __PT_PARM5_SYSCALL_REG __PT_PARM5_REG 436 | #define __PT_PARM6_SYSCALL_REG __PT_PARM6_REG 437 | 438 | #define __PT_RET_REG regs[1] 439 | #define __PT_FP_REG regs[22] 440 | #define __PT_RC_REG regs[4] 441 | #define __PT_SP_REG regs[3] 442 | #define __PT_IP_REG csr_era 443 | 444 | #endif 445 | 446 | #if defined(bpf_target_defined) 447 | 448 | struct pt_regs; 449 | 450 | /* allow some architectures to override `struct pt_regs` */ 451 | #ifndef __PT_REGS_CAST 452 | #define __PT_REGS_CAST(x) (x) 453 | #endif 454 | 455 | /* 456 | * Different architectures support different number of arguments passed 457 | * through registers. i386 supports just 3, some arches support up to 8. 458 | */ 459 | #ifndef __PT_PARM4_REG 460 | #define __PT_PARM4_REG __unsupported__ 461 | #endif 462 | #ifndef __PT_PARM5_REG 463 | #define __PT_PARM5_REG __unsupported__ 464 | #endif 465 | #ifndef __PT_PARM6_REG 466 | #define __PT_PARM6_REG __unsupported__ 467 | #endif 468 | #ifndef __PT_PARM7_REG 469 | #define __PT_PARM7_REG __unsupported__ 470 | #endif 471 | #ifndef __PT_PARM8_REG 472 | #define __PT_PARM8_REG __unsupported__ 473 | #endif 474 | /* 475 | * Similarly, syscall-specific conventions might differ between function call 476 | * conventions within each architecutre. All supported architectures pass 477 | * either 6 or 7 syscall arguments in registers. 478 | * 479 | * See syscall(2) manpage for succinct table with information on each arch. 480 | */ 481 | #ifndef __PT_PARM7_SYSCALL_REG 482 | #define __PT_PARM7_SYSCALL_REG __unsupported__ 483 | #endif 484 | 485 | #define PT_REGS_PARM1(x) (__PT_REGS_CAST(x)->__PT_PARM1_REG) 486 | #define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG) 487 | #define PT_REGS_PARM3(x) (__PT_REGS_CAST(x)->__PT_PARM3_REG) 488 | #define PT_REGS_PARM4(x) (__PT_REGS_CAST(x)->__PT_PARM4_REG) 489 | #define PT_REGS_PARM5(x) (__PT_REGS_CAST(x)->__PT_PARM5_REG) 490 | #define PT_REGS_PARM6(x) (__PT_REGS_CAST(x)->__PT_PARM6_REG) 491 | #define PT_REGS_PARM7(x) (__PT_REGS_CAST(x)->__PT_PARM7_REG) 492 | #define PT_REGS_PARM8(x) (__PT_REGS_CAST(x)->__PT_PARM8_REG) 493 | #define PT_REGS_RET(x) (__PT_REGS_CAST(x)->__PT_RET_REG) 494 | #define PT_REGS_FP(x) (__PT_REGS_CAST(x)->__PT_FP_REG) 495 | #define PT_REGS_RC(x) (__PT_REGS_CAST(x)->__PT_RC_REG) 496 | #define PT_REGS_SP(x) (__PT_REGS_CAST(x)->__PT_SP_REG) 497 | #define PT_REGS_IP(x) (__PT_REGS_CAST(x)->__PT_IP_REG) 498 | 499 | #define PT_REGS_PARM1_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_REG) 500 | #define PT_REGS_PARM2_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_REG) 501 | #define PT_REGS_PARM3_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_REG) 502 | #define PT_REGS_PARM4_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_REG) 503 | #define PT_REGS_PARM5_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_REG) 504 | #define PT_REGS_PARM6_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_REG) 505 | #define PT_REGS_PARM7_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_REG) 506 | #define PT_REGS_PARM8_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM8_REG) 507 | #define PT_REGS_RET_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RET_REG) 508 | #define PT_REGS_FP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_FP_REG) 509 | #define PT_REGS_RC_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_RC_REG) 510 | #define PT_REGS_SP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_SP_REG) 511 | #define PT_REGS_IP_CORE(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_IP_REG) 512 | 513 | #if defined(bpf_target_powerpc) 514 | 515 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 516 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 517 | 518 | #elif defined(bpf_target_sparc) 519 | 520 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) 521 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 522 | 523 | #else 524 | 525 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) \ 526 | ({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 527 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ 528 | ({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 529 | 530 | #endif 531 | 532 | #ifndef PT_REGS_PARM1_SYSCALL 533 | #define PT_REGS_PARM1_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM1_SYSCALL_REG) 534 | #define PT_REGS_PARM1_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM1_SYSCALL_REG) 535 | #endif 536 | #ifndef PT_REGS_PARM2_SYSCALL 537 | #define PT_REGS_PARM2_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM2_SYSCALL_REG) 538 | #define PT_REGS_PARM2_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM2_SYSCALL_REG) 539 | #endif 540 | #ifndef PT_REGS_PARM3_SYSCALL 541 | #define PT_REGS_PARM3_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM3_SYSCALL_REG) 542 | #define PT_REGS_PARM3_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM3_SYSCALL_REG) 543 | #endif 544 | #ifndef PT_REGS_PARM4_SYSCALL 545 | #define PT_REGS_PARM4_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM4_SYSCALL_REG) 546 | #define PT_REGS_PARM4_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM4_SYSCALL_REG) 547 | #endif 548 | #ifndef PT_REGS_PARM5_SYSCALL 549 | #define PT_REGS_PARM5_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM5_SYSCALL_REG) 550 | #define PT_REGS_PARM5_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM5_SYSCALL_REG) 551 | #endif 552 | #ifndef PT_REGS_PARM6_SYSCALL 553 | #define PT_REGS_PARM6_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM6_SYSCALL_REG) 554 | #define PT_REGS_PARM6_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM6_SYSCALL_REG) 555 | #endif 556 | #ifndef PT_REGS_PARM7_SYSCALL 557 | #define PT_REGS_PARM7_SYSCALL(x) (__PT_REGS_CAST(x)->__PT_PARM7_SYSCALL_REG) 558 | #define PT_REGS_PARM7_CORE_SYSCALL(x) BPF_CORE_READ(__PT_REGS_CAST(x), __PT_PARM7_SYSCALL_REG) 559 | #endif 560 | 561 | #else /* defined(bpf_target_defined) */ 562 | 563 | #define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 564 | #define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 565 | #define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 566 | #define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 567 | #define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 568 | #define PT_REGS_PARM6(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 569 | #define PT_REGS_PARM7(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 570 | #define PT_REGS_PARM8(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 571 | #define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 572 | #define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 573 | #define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 574 | #define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 575 | #define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 576 | 577 | #define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 578 | #define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 579 | #define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 580 | #define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 581 | #define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 582 | #define PT_REGS_PARM6_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 583 | #define PT_REGS_PARM7_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 584 | #define PT_REGS_PARM8_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 585 | #define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 586 | #define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 587 | #define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 588 | #define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 589 | #define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 590 | 591 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 592 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 593 | 594 | #define PT_REGS_PARM1_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 595 | #define PT_REGS_PARM2_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 596 | #define PT_REGS_PARM3_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 597 | #define PT_REGS_PARM4_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 598 | #define PT_REGS_PARM5_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 599 | #define PT_REGS_PARM6_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 600 | #define PT_REGS_PARM7_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 601 | 602 | #define PT_REGS_PARM1_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 603 | #define PT_REGS_PARM2_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 604 | #define PT_REGS_PARM3_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 605 | #define PT_REGS_PARM4_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 606 | #define PT_REGS_PARM5_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 607 | #define PT_REGS_PARM6_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 608 | #define PT_REGS_PARM7_CORE_SYSCALL(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; }) 609 | 610 | #endif /* defined(bpf_target_defined) */ 611 | 612 | /* 613 | * When invoked from a syscall handler kprobe, returns a pointer to a 614 | * struct pt_regs containing syscall arguments and suitable for passing to 615 | * PT_REGS_PARMn_SYSCALL() and PT_REGS_PARMn_CORE_SYSCALL(). 616 | */ 617 | #ifndef PT_REGS_SYSCALL_REGS 618 | /* By default, assume that the arch selects ARCH_HAS_SYSCALL_WRAPPER. */ 619 | #define PT_REGS_SYSCALL_REGS(ctx) ((struct pt_regs *)PT_REGS_PARM1(ctx)) 620 | #endif 621 | 622 | #ifndef ___bpf_concat 623 | #define ___bpf_concat(a, b) a ## b 624 | #endif 625 | #ifndef ___bpf_apply 626 | #define ___bpf_apply(fn, n) ___bpf_concat(fn, n) 627 | #endif 628 | #ifndef ___bpf_nth 629 | #define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N 630 | #endif 631 | #ifndef ___bpf_narg 632 | #define ___bpf_narg(...) ___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 633 | #endif 634 | 635 | #define ___bpf_ctx_cast0() ctx 636 | #define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0] 637 | #define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1] 638 | #define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2] 639 | #define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3] 640 | #define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4] 641 | #define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5] 642 | #define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6] 643 | #define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7] 644 | #define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8] 645 | #define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9] 646 | #define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10] 647 | #define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11] 648 | #define ___bpf_ctx_cast(args...) ___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args) 649 | 650 | /* 651 | * BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and 652 | * similar kinds of BPF programs, that accept input arguments as a single 653 | * pointer to untyped u64 array, where each u64 can actually be a typed 654 | * pointer or integer of different size. Instead of requring user to write 655 | * manual casts and work with array elements by index, BPF_PROG macro 656 | * allows user to declare a list of named and typed input arguments in the 657 | * same syntax as for normal C function. All the casting is hidden and 658 | * performed transparently, while user code can just assume working with 659 | * function arguments of specified type and name. 660 | * 661 | * Original raw context argument is preserved as well as 'ctx' argument. 662 | * This is useful when using BPF helpers that expect original context 663 | * as one of the parameters (e.g., for bpf_perf_event_output()). 664 | */ 665 | #define BPF_PROG(name, args...) \ 666 | name(unsigned long long *ctx); \ 667 | static __always_inline typeof(name(0)) \ 668 | ____##name(unsigned long long *ctx, ##args); \ 669 | typeof(name(0)) name(unsigned long long *ctx) \ 670 | { \ 671 | _Pragma("GCC diagnostic push") \ 672 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 673 | return ____##name(___bpf_ctx_cast(args)); \ 674 | _Pragma("GCC diagnostic pop") \ 675 | } \ 676 | static __always_inline typeof(name(0)) \ 677 | ____##name(unsigned long long *ctx, ##args) 678 | 679 | #ifndef ___bpf_nth2 680 | #define ___bpf_nth2(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \ 681 | _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, N, ...) N 682 | #endif 683 | #ifndef ___bpf_narg2 684 | #define ___bpf_narg2(...) \ 685 | ___bpf_nth2(_, ##__VA_ARGS__, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, \ 686 | 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0) 687 | #endif 688 | 689 | #define ___bpf_treg_cnt(t) \ 690 | __builtin_choose_expr(sizeof(t) == 1, 1, \ 691 | __builtin_choose_expr(sizeof(t) == 2, 1, \ 692 | __builtin_choose_expr(sizeof(t) == 4, 1, \ 693 | __builtin_choose_expr(sizeof(t) == 8, 1, \ 694 | __builtin_choose_expr(sizeof(t) == 16, 2, \ 695 | (void)0))))) 696 | 697 | #define ___bpf_reg_cnt0() (0) 698 | #define ___bpf_reg_cnt1(t, x) (___bpf_reg_cnt0() + ___bpf_treg_cnt(t)) 699 | #define ___bpf_reg_cnt2(t, x, args...) (___bpf_reg_cnt1(args) + ___bpf_treg_cnt(t)) 700 | #define ___bpf_reg_cnt3(t, x, args...) (___bpf_reg_cnt2(args) + ___bpf_treg_cnt(t)) 701 | #define ___bpf_reg_cnt4(t, x, args...) (___bpf_reg_cnt3(args) + ___bpf_treg_cnt(t)) 702 | #define ___bpf_reg_cnt5(t, x, args...) (___bpf_reg_cnt4(args) + ___bpf_treg_cnt(t)) 703 | #define ___bpf_reg_cnt6(t, x, args...) (___bpf_reg_cnt5(args) + ___bpf_treg_cnt(t)) 704 | #define ___bpf_reg_cnt7(t, x, args...) (___bpf_reg_cnt6(args) + ___bpf_treg_cnt(t)) 705 | #define ___bpf_reg_cnt8(t, x, args...) (___bpf_reg_cnt7(args) + ___bpf_treg_cnt(t)) 706 | #define ___bpf_reg_cnt9(t, x, args...) (___bpf_reg_cnt8(args) + ___bpf_treg_cnt(t)) 707 | #define ___bpf_reg_cnt10(t, x, args...) (___bpf_reg_cnt9(args) + ___bpf_treg_cnt(t)) 708 | #define ___bpf_reg_cnt11(t, x, args...) (___bpf_reg_cnt10(args) + ___bpf_treg_cnt(t)) 709 | #define ___bpf_reg_cnt12(t, x, args...) (___bpf_reg_cnt11(args) + ___bpf_treg_cnt(t)) 710 | #define ___bpf_reg_cnt(args...) ___bpf_apply(___bpf_reg_cnt, ___bpf_narg2(args))(args) 711 | 712 | #define ___bpf_union_arg(t, x, n) \ 713 | __builtin_choose_expr(sizeof(t) == 1, ({ union { __u8 z[1]; t x; } ___t = { .z = {ctx[n]}}; ___t.x; }), \ 714 | __builtin_choose_expr(sizeof(t) == 2, ({ union { __u16 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \ 715 | __builtin_choose_expr(sizeof(t) == 4, ({ union { __u32 z[1]; t x; } ___t = { .z = {ctx[n]} }; ___t.x; }), \ 716 | __builtin_choose_expr(sizeof(t) == 8, ({ union { __u64 z[1]; t x; } ___t = {.z = {ctx[n]} }; ___t.x; }), \ 717 | __builtin_choose_expr(sizeof(t) == 16, ({ union { __u64 z[2]; t x; } ___t = {.z = {ctx[n], ctx[n + 1]} }; ___t.x; }), \ 718 | (void)0))))) 719 | 720 | #define ___bpf_ctx_arg0(n, args...) 721 | #define ___bpf_ctx_arg1(n, t, x) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt1(t, x)) 722 | #define ___bpf_ctx_arg2(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt2(t, x, args)) ___bpf_ctx_arg1(n, args) 723 | #define ___bpf_ctx_arg3(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt3(t, x, args)) ___bpf_ctx_arg2(n, args) 724 | #define ___bpf_ctx_arg4(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt4(t, x, args)) ___bpf_ctx_arg3(n, args) 725 | #define ___bpf_ctx_arg5(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt5(t, x, args)) ___bpf_ctx_arg4(n, args) 726 | #define ___bpf_ctx_arg6(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt6(t, x, args)) ___bpf_ctx_arg5(n, args) 727 | #define ___bpf_ctx_arg7(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt7(t, x, args)) ___bpf_ctx_arg6(n, args) 728 | #define ___bpf_ctx_arg8(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt8(t, x, args)) ___bpf_ctx_arg7(n, args) 729 | #define ___bpf_ctx_arg9(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt9(t, x, args)) ___bpf_ctx_arg8(n, args) 730 | #define ___bpf_ctx_arg10(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt10(t, x, args)) ___bpf_ctx_arg9(n, args) 731 | #define ___bpf_ctx_arg11(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt11(t, x, args)) ___bpf_ctx_arg10(n, args) 732 | #define ___bpf_ctx_arg12(n, t, x, args...) , ___bpf_union_arg(t, x, n - ___bpf_reg_cnt12(t, x, args)) ___bpf_ctx_arg11(n, args) 733 | #define ___bpf_ctx_arg(args...) ___bpf_apply(___bpf_ctx_arg, ___bpf_narg2(args))(___bpf_reg_cnt(args), args) 734 | 735 | #define ___bpf_ctx_decl0() 736 | #define ___bpf_ctx_decl1(t, x) , t x 737 | #define ___bpf_ctx_decl2(t, x, args...) , t x ___bpf_ctx_decl1(args) 738 | #define ___bpf_ctx_decl3(t, x, args...) , t x ___bpf_ctx_decl2(args) 739 | #define ___bpf_ctx_decl4(t, x, args...) , t x ___bpf_ctx_decl3(args) 740 | #define ___bpf_ctx_decl5(t, x, args...) , t x ___bpf_ctx_decl4(args) 741 | #define ___bpf_ctx_decl6(t, x, args...) , t x ___bpf_ctx_decl5(args) 742 | #define ___bpf_ctx_decl7(t, x, args...) , t x ___bpf_ctx_decl6(args) 743 | #define ___bpf_ctx_decl8(t, x, args...) , t x ___bpf_ctx_decl7(args) 744 | #define ___bpf_ctx_decl9(t, x, args...) , t x ___bpf_ctx_decl8(args) 745 | #define ___bpf_ctx_decl10(t, x, args...) , t x ___bpf_ctx_decl9(args) 746 | #define ___bpf_ctx_decl11(t, x, args...) , t x ___bpf_ctx_decl10(args) 747 | #define ___bpf_ctx_decl12(t, x, args...) , t x ___bpf_ctx_decl11(args) 748 | #define ___bpf_ctx_decl(args...) ___bpf_apply(___bpf_ctx_decl, ___bpf_narg2(args))(args) 749 | 750 | /* 751 | * BPF_PROG2 is an enhanced version of BPF_PROG in order to handle struct 752 | * arguments. Since each struct argument might take one or two u64 values 753 | * in the trampoline stack, argument type size is needed to place proper number 754 | * of u64 values for each argument. Therefore, BPF_PROG2 has different 755 | * syntax from BPF_PROG. For example, for the following BPF_PROG syntax: 756 | * 757 | * int BPF_PROG(test2, int a, int b) { ... } 758 | * 759 | * the corresponding BPF_PROG2 syntax is: 760 | * 761 | * int BPF_PROG2(test2, int, a, int, b) { ... } 762 | * 763 | * where type and the corresponding argument name are separated by comma. 764 | * 765 | * Use BPF_PROG2 macro if one of the arguments might be a struct/union larger 766 | * than 8 bytes: 767 | * 768 | * int BPF_PROG2(test_struct_arg, struct bpf_testmod_struct_arg_1, a, int, b, 769 | * int, c, int, d, struct bpf_testmod_struct_arg_2, e, int, ret) 770 | * { 771 | * // access a, b, c, d, e, and ret directly 772 | * ... 773 | * } 774 | */ 775 | #define BPF_PROG2(name, args...) \ 776 | name(unsigned long long *ctx); \ 777 | static __always_inline typeof(name(0)) \ 778 | ____##name(unsigned long long *ctx ___bpf_ctx_decl(args)); \ 779 | typeof(name(0)) name(unsigned long long *ctx) \ 780 | { \ 781 | return ____##name(ctx ___bpf_ctx_arg(args)); \ 782 | } \ 783 | static __always_inline typeof(name(0)) \ 784 | ____##name(unsigned long long *ctx ___bpf_ctx_decl(args)) 785 | 786 | struct pt_regs; 787 | 788 | #define ___bpf_kprobe_args0() ctx 789 | #define ___bpf_kprobe_args1(x) ___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx) 790 | #define ___bpf_kprobe_args2(x, args...) ___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx) 791 | #define ___bpf_kprobe_args3(x, args...) ___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx) 792 | #define ___bpf_kprobe_args4(x, args...) ___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx) 793 | #define ___bpf_kprobe_args5(x, args...) ___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx) 794 | #define ___bpf_kprobe_args6(x, args...) ___bpf_kprobe_args5(args), (void *)PT_REGS_PARM6(ctx) 795 | #define ___bpf_kprobe_args7(x, args...) ___bpf_kprobe_args6(args), (void *)PT_REGS_PARM7(ctx) 796 | #define ___bpf_kprobe_args8(x, args...) ___bpf_kprobe_args7(args), (void *)PT_REGS_PARM8(ctx) 797 | #define ___bpf_kprobe_args(args...) ___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args) 798 | 799 | /* 800 | * BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for 801 | * tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific 802 | * low-level way of getting kprobe input arguments from struct pt_regs, and 803 | * provides a familiar typed and named function arguments syntax and 804 | * semantics of accessing kprobe input paremeters. 805 | * 806 | * Original struct pt_regs* context is preserved as 'ctx' argument. This might 807 | * be necessary when using BPF helpers like bpf_perf_event_output(). 808 | */ 809 | #define BPF_KPROBE(name, args...) \ 810 | name(struct pt_regs *ctx); \ 811 | static __always_inline typeof(name(0)) \ 812 | ____##name(struct pt_regs *ctx, ##args); \ 813 | typeof(name(0)) name(struct pt_regs *ctx) \ 814 | { \ 815 | _Pragma("GCC diagnostic push") \ 816 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 817 | return ____##name(___bpf_kprobe_args(args)); \ 818 | _Pragma("GCC diagnostic pop") \ 819 | } \ 820 | static __always_inline typeof(name(0)) \ 821 | ____##name(struct pt_regs *ctx, ##args) 822 | 823 | #define ___bpf_kretprobe_args0() ctx 824 | #define ___bpf_kretprobe_args1(x) ___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx) 825 | #define ___bpf_kretprobe_args(args...) ___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args) 826 | 827 | /* 828 | * BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional 829 | * return value (in addition to `struct pt_regs *ctx`), but no input 830 | * arguments, because they will be clobbered by the time probed function 831 | * returns. 832 | */ 833 | #define BPF_KRETPROBE(name, args...) \ 834 | name(struct pt_regs *ctx); \ 835 | static __always_inline typeof(name(0)) \ 836 | ____##name(struct pt_regs *ctx, ##args); \ 837 | typeof(name(0)) name(struct pt_regs *ctx) \ 838 | { \ 839 | _Pragma("GCC diagnostic push") \ 840 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 841 | return ____##name(___bpf_kretprobe_args(args)); \ 842 | _Pragma("GCC diagnostic pop") \ 843 | } \ 844 | static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) 845 | 846 | /* If kernel has CONFIG_ARCH_HAS_SYSCALL_WRAPPER, read pt_regs directly */ 847 | #define ___bpf_syscall_args0() ctx 848 | #define ___bpf_syscall_args1(x) ___bpf_syscall_args0(), (void *)PT_REGS_PARM1_SYSCALL(regs) 849 | #define ___bpf_syscall_args2(x, args...) ___bpf_syscall_args1(args), (void *)PT_REGS_PARM2_SYSCALL(regs) 850 | #define ___bpf_syscall_args3(x, args...) ___bpf_syscall_args2(args), (void *)PT_REGS_PARM3_SYSCALL(regs) 851 | #define ___bpf_syscall_args4(x, args...) ___bpf_syscall_args3(args), (void *)PT_REGS_PARM4_SYSCALL(regs) 852 | #define ___bpf_syscall_args5(x, args...) ___bpf_syscall_args4(args), (void *)PT_REGS_PARM5_SYSCALL(regs) 853 | #define ___bpf_syscall_args6(x, args...) ___bpf_syscall_args5(args), (void *)PT_REGS_PARM6_SYSCALL(regs) 854 | #define ___bpf_syscall_args7(x, args...) ___bpf_syscall_args6(args), (void *)PT_REGS_PARM7_SYSCALL(regs) 855 | #define ___bpf_syscall_args(args...) ___bpf_apply(___bpf_syscall_args, ___bpf_narg(args))(args) 856 | 857 | /* If kernel doesn't have CONFIG_ARCH_HAS_SYSCALL_WRAPPER, we have to BPF_CORE_READ from pt_regs */ 858 | #define ___bpf_syswrap_args0() ctx 859 | #define ___bpf_syswrap_args1(x) ___bpf_syswrap_args0(), (void *)PT_REGS_PARM1_CORE_SYSCALL(regs) 860 | #define ___bpf_syswrap_args2(x, args...) ___bpf_syswrap_args1(args), (void *)PT_REGS_PARM2_CORE_SYSCALL(regs) 861 | #define ___bpf_syswrap_args3(x, args...) ___bpf_syswrap_args2(args), (void *)PT_REGS_PARM3_CORE_SYSCALL(regs) 862 | #define ___bpf_syswrap_args4(x, args...) ___bpf_syswrap_args3(args), (void *)PT_REGS_PARM4_CORE_SYSCALL(regs) 863 | #define ___bpf_syswrap_args5(x, args...) ___bpf_syswrap_args4(args), (void *)PT_REGS_PARM5_CORE_SYSCALL(regs) 864 | #define ___bpf_syswrap_args6(x, args...) ___bpf_syswrap_args5(args), (void *)PT_REGS_PARM6_CORE_SYSCALL(regs) 865 | #define ___bpf_syswrap_args7(x, args...) ___bpf_syswrap_args6(args), (void *)PT_REGS_PARM7_CORE_SYSCALL(regs) 866 | #define ___bpf_syswrap_args(args...) ___bpf_apply(___bpf_syswrap_args, ___bpf_narg(args))(args) 867 | 868 | /* 869 | * BPF_KSYSCALL is a variant of BPF_KPROBE, which is intended for 870 | * tracing syscall functions, like __x64_sys_close. It hides the underlying 871 | * platform-specific low-level way of getting syscall input arguments from 872 | * struct pt_regs, and provides a familiar typed and named function arguments 873 | * syntax and semantics of accessing syscall input parameters. 874 | * 875 | * Original struct pt_regs * context is preserved as 'ctx' argument. This might 876 | * be necessary when using BPF helpers like bpf_perf_event_output(). 877 | * 878 | * At the moment BPF_KSYSCALL does not transparently handle all the calling 879 | * convention quirks for the following syscalls: 880 | * 881 | * - mmap(): __ARCH_WANT_SYS_OLD_MMAP. 882 | * - clone(): CONFIG_CLONE_BACKWARDS, CONFIG_CLONE_BACKWARDS2 and 883 | * CONFIG_CLONE_BACKWARDS3. 884 | * - socket-related syscalls: __ARCH_WANT_SYS_SOCKETCALL. 885 | * - compat syscalls. 886 | * 887 | * This may or may not change in the future. User needs to take extra measures 888 | * to handle such quirks explicitly, if necessary. 889 | * 890 | * This macro relies on BPF CO-RE support and virtual __kconfig externs. 891 | */ 892 | #define BPF_KSYSCALL(name, args...) \ 893 | name(struct pt_regs *ctx); \ 894 | extern _Bool LINUX_HAS_SYSCALL_WRAPPER __kconfig; \ 895 | static __always_inline typeof(name(0)) \ 896 | ____##name(struct pt_regs *ctx, ##args); \ 897 | typeof(name(0)) name(struct pt_regs *ctx) \ 898 | { \ 899 | struct pt_regs *regs = LINUX_HAS_SYSCALL_WRAPPER \ 900 | ? (struct pt_regs *)PT_REGS_PARM1(ctx) \ 901 | : ctx; \ 902 | _Pragma("GCC diagnostic push") \ 903 | _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ 904 | if (LINUX_HAS_SYSCALL_WRAPPER) \ 905 | return ____##name(___bpf_syswrap_args(args)); \ 906 | else \ 907 | return ____##name(___bpf_syscall_args(args)); \ 908 | _Pragma("GCC diagnostic pop") \ 909 | } \ 910 | static __always_inline typeof(name(0)) \ 911 | ____##name(struct pt_regs *ctx, ##args) 912 | 913 | #define BPF_KPROBE_SYSCALL BPF_KSYSCALL 914 | 915 | /* BPF_UPROBE and BPF_URETPROBE are identical to BPF_KPROBE and BPF_KRETPROBE, 916 | * but are named way less confusingly for SEC("uprobe") and SEC("uretprobe") 917 | * use cases. 918 | */ 919 | #define BPF_UPROBE(name, args...) BPF_KPROBE(name, ##args) 920 | #define BPF_URETPROBE(name, args...) BPF_KRETPROBE(name, ##args) 921 | 922 | #endif 923 | -------------------------------------------------------------------------------- /bpf/headers/errno-base.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _ASM_GENERIC_ERRNO_BASE_H 3 | #define _ASM_GENERIC_ERRNO_BASE_H 4 | 5 | #define EPERM 1 /* Operation not permitted */ 6 | #define ENOENT 2 /* No such file or directory */ 7 | #define ESRCH 3 /* No such process */ 8 | #define EINTR 4 /* Interrupted system call */ 9 | #define EIO 5 /* I/O error */ 10 | #define ENXIO 6 /* No such device or address */ 11 | #define E2BIG 7 /* Argument list too long */ 12 | #define ENOEXEC 8 /* Exec format error */ 13 | #define EBADF 9 /* Bad file number */ 14 | #define ECHILD 10 /* No child processes */ 15 | #define EAGAIN 11 /* Try again */ 16 | #define ENOMEM 12 /* Out of memory */ 17 | #define EACCES 13 /* Permission denied */ 18 | #define EFAULT 14 /* Bad address */ 19 | #define ENOTBLK 15 /* Block device required */ 20 | #define EBUSY 16 /* Device or resource busy */ 21 | #define EEXIST 17 /* File exists */ 22 | #define EXDEV 18 /* Cross-device link */ 23 | #define ENODEV 19 /* No such device */ 24 | #define ENOTDIR 20 /* Not a directory */ 25 | #define EISDIR 21 /* Is a directory */ 26 | #define EINVAL 22 /* Invalid argument */ 27 | #define ENFILE 23 /* File table overflow */ 28 | #define EMFILE 24 /* Too many open files */ 29 | #define ENOTTY 25 /* Not a typewriter */ 30 | #define ETXTBSY 26 /* Text file busy */ 31 | #define EFBIG 27 /* File too large */ 32 | #define ENOSPC 28 /* No space left on device */ 33 | #define ESPIPE 29 /* Illegal seek */ 34 | #define EROFS 30 /* Read-only file system */ 35 | #define EMLINK 31 /* Too many links */ 36 | #define EPIPE 32 /* Broken pipe */ 37 | #define EDOM 33 /* Math argument out of domain of func */ 38 | #define ERANGE 34 /* Math result not representable */ 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /bpf/headers/if_ether_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef __IF_ETHER_DEFS_H__ 2 | #define __IF_ETHER_DEFS_H__ 3 | /* 4 | * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble 5 | * and FCS/CRC (frame check sequence). 6 | */ 7 | 8 | #define ETH_ALEN 6 /* Octets in one ethernet addr */ 9 | #define ETH_TLEN 2 /* Octets in ethernet type field */ 10 | #define ETH_HLEN 14 /* Total octets in header. */ 11 | #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ 12 | #define ETH_DATA_LEN 1500 /* Max. octets in payload */ 13 | #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ 14 | #define ETH_FCS_LEN 4 /* Octets in the FCS */ 15 | 16 | #define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */ 17 | #define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */ 18 | 19 | /* 20 | * These are the defined Ethernet Protocol ID's. 21 | */ 22 | 23 | #define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ 24 | #define ETH_P_PUP 0x0200 /* Xerox PUP packet */ 25 | #define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ 26 | #define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */ 27 | #define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */ 28 | #define ETH_P_IP 0x0800 /* Internet Protocol packet */ 29 | #define ETH_P_X25 0x0805 /* CCITT X.25 */ 30 | #define ETH_P_ARP 0x0806 /* Address Resolution packet */ 31 | #define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */ 32 | #define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ 33 | #define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */ 34 | #define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet [ NOT AN OFFICIALLY REGISTERED ID ] */ 35 | #define ETH_P_DEC 0x6000 /* DEC Assigned proto */ 36 | #define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ 37 | #define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ 38 | #define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ 39 | #define ETH_P_LAT 0x6004 /* DEC LAT */ 40 | #define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ 41 | #define ETH_P_CUST 0x6006 /* DEC Customer use */ 42 | #define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ 43 | #define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ 44 | #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ 45 | #define ETH_P_ATALK 0x809B /* Appletalk DDP */ 46 | #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ 47 | #define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ 48 | #define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */ 49 | #define ETH_P_IPX 0x8137 /* IPX over DIX */ 50 | #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ 51 | #define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */ 52 | #define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */ 53 | #define ETH_P_WCCP 0x883E /* Web-cache coordination protocol 54 | * defined in draft-wilson-wrec-wccp-v2-00.txt */ 55 | #define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ 56 | #define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ 57 | #define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ 58 | #define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ 59 | #define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ 60 | #define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */ 61 | #define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport 62 | * over Ethernet 63 | */ 64 | #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ 65 | #define ETH_P_PROFINET 0x8892 /* PROFINET */ 66 | #define ETH_P_REALTEK 0x8899 /* Multiple proprietary protocols */ 67 | #define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ 68 | #define ETH_P_ETHERCAT 0x88A4 /* EtherCAT */ 69 | #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ 70 | #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ 71 | #define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ 72 | #define ETH_P_TIPC 0x88CA /* TIPC */ 73 | #define ETH_P_LLDP 0x88CC /* Link Layer Discovery Protocol */ 74 | #define ETH_P_MRP 0x88E3 /* Media Redundancy Protocol */ 75 | #define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ 76 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ 77 | #define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ 78 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ 79 | #define ETH_P_NCSI 0x88F8 /* NCSI protocol */ 80 | #define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */ 81 | #define ETH_P_CFM 0x8902 /* Connectivity Fault Management */ 82 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ 83 | #define ETH_P_IBOE 0x8915 /* Infiniband over Ethernet */ 84 | #define ETH_P_TDLS 0x890D /* TDLS */ 85 | #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ 86 | #define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */ 87 | #define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */ 88 | #define ETH_P_NSH 0x894F /* Network Service Header */ 89 | #define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ 90 | #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ 91 | #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ 92 | #define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ 93 | #define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ 94 | #define ETH_P_DSA_8021Q 0xDADB /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ 95 | #define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */ 96 | #define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */ 97 | 98 | #define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is more than this value 99 | * then the frame is Ethernet II. Else it is 802.3 */ 100 | 101 | /* 102 | * Non DIX types. Won't clash for 1500 types. 103 | */ 104 | 105 | #define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ 106 | #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ 107 | #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ 108 | #define ETH_P_802_2 0x0004 /* 802.2 frames */ 109 | #define ETH_P_SNAP 0x0005 /* Internal only */ 110 | #define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ 111 | #define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ 112 | #define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ 113 | #define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ 114 | #define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ 115 | #define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ 116 | #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ 117 | #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ 118 | #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ 119 | #define ETH_P_CONTROL 0x0016 /* Card specific control frames */ 120 | #define ETH_P_IRDA 0x0017 /* Linux-IrDA */ 121 | #define ETH_P_ECONET 0x0018 /* Acorn Econet */ 122 | #define ETH_P_HDLC 0x0019 /* HDLC frames */ 123 | #define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ 124 | #define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ 125 | #define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ 126 | #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ 127 | #define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ 128 | #define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ 129 | #define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */ 130 | #define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and 131 | * aggregation protocol 132 | */ 133 | #define ETH_P_MCTP 0x00FA /* Management component transport 134 | * protocol packets 135 | */ 136 | 137 | #endif -------------------------------------------------------------------------------- /bpf/headers/pkt_cls_defs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __PKT_CLS_DEFS_H__ 3 | #define __PKT_CLS_DEFS_H__ 4 | 5 | #define TC_COOKIE_MAX_SIZE 16 6 | 7 | /* Action attributes */ 8 | 9 | /* See other TCA_ACT_FLAGS_ * flags in include/net/act_api.h. */ 10 | #define TCA_ACT_FLAGS_NO_PERCPU_STATS \ 11 | (1 << 0) /* Don't use percpu allocator for \ 12 | * actions stats. \ 13 | */ 14 | #define TCA_ACT_FLAGS_SKIP_HW (1 << 1) /* don't offload action to HW */ 15 | #define TCA_ACT_FLAGS_SKIP_SW (1 << 2) /* don't use action in SW */ 16 | 17 | /* tca HW stats type 18 | * When user does not pass the attribute, he does not care. 19 | * It is the same as if he would pass the attribute with 20 | * all supported bits set. 21 | * In case no bits are set, user is not interested in getting any HW statistics. 22 | */ 23 | #define TCA_ACT_HW_STATS_IMMEDIATE \ 24 | (1 << 0) /* Means that in dump, user \ 25 | * gets the current HW stats \ 26 | * state from the device \ 27 | * queried at the dump time. \ 28 | */ 29 | #define TCA_ACT_HW_STATS_DELAYED \ 30 | (1 << 1) /* Means that in dump, user gets \ 31 | * HW stats that might be out of date \ 32 | * for some time, maybe couple of \ 33 | * seconds. This is the case when \ 34 | * driver polls stats updates \ 35 | * periodically or when it gets async \ 36 | * stats update from the device. \ 37 | */ 38 | 39 | #define TCA_ACT_MAX __TCA_ACT_MAX 40 | #define TCA_OLD_COMPAT (TCA_ACT_MAX + 1) 41 | #define TCA_ACT_MAX_PRIO 32 42 | #define TCA_ACT_BIND 1 43 | #define TCA_ACT_NOBIND 0 44 | #define TCA_ACT_UNBIND 1 45 | #define TCA_ACT_NOUNBIND 0 46 | #define TCA_ACT_REPLACE 1 47 | #define TCA_ACT_NOREPLACE 0 48 | 49 | #define TC_ACT_UNSPEC (-1) 50 | #define TC_ACT_OK 0 51 | #define TC_ACT_RECLASSIFY 1 52 | #define TC_ACT_SHOT 2 53 | #define TC_ACT_PIPE 3 54 | #define TC_ACT_STOLEN 4 55 | #define TC_ACT_QUEUED 5 56 | #define TC_ACT_REPEAT 6 57 | #define TC_ACT_REDIRECT 7 58 | #define TC_ACT_TRAP 8 59 | /* For hw path, this means "trap to cpu" 60 | * and don't further process the frame 61 | * in hardware. For sw path, this is 62 | * equivalent of TC_ACT_STOLEN - drop 63 | * the skb and act like everything 64 | * is alright. 65 | */ 66 | #define TC_ACT_VALUE_MAX TC_ACT_TRAP 67 | 68 | /* There is a special kind of actions called "extended actions", 69 | * which need a value parameter. These have a local opcode located in 70 | * the highest nibble, starting from 1. The rest of the bits 71 | * are used to carry the value. These two parts together make 72 | * a combined opcode. 73 | */ 74 | #define __TC_ACT_EXT_SHIFT 28 75 | #define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT) 76 | #define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1) 77 | #define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK)) 78 | #define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode) 79 | 80 | #define TC_ACT_JUMP __TC_ACT_EXT(1) 81 | #define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) 82 | #define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN 83 | 84 | /* These macros are put here for binary compatibility with userspace apps that 85 | * make use of them. For kernel code and new userspace apps, use the TCA_ID_* 86 | * versions. 87 | */ 88 | #define TCA_ACT_GACT 5 89 | #define TCA_ACT_IPT 6 90 | #define TCA_ACT_PEDIT 7 91 | #define TCA_ACT_MIRRED 8 92 | #define TCA_ACT_NAT 9 93 | #define TCA_ACT_XT 10 94 | #define TCA_ACT_SKBEDIT 11 95 | #define TCA_ACT_VLAN 12 96 | #define TCA_ACT_BPF 13 97 | #define TCA_ACT_CONNMARK 14 98 | #define TCA_ACT_SKBMOD 15 99 | #define TCA_ACT_CSUM 16 100 | #define TCA_ACT_TUNNEL_KEY 17 101 | #define TCA_ACT_SIMP 22 102 | #define TCA_ACT_IFE 25 103 | #define TCA_ACT_SAMPLE 26 104 | 105 | #endif -------------------------------------------------------------------------------- /bpf/headers/socket_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOCKET_DEFS_H__ 2 | #define __SOCKET_DEFS_H__ 3 | 4 | /* Supported address families. */ 5 | #define AF_UNSPEC 0 6 | #define AF_UNIX 1 /* Unix domain sockets */ 7 | #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ 8 | #define AF_INET 2 /* Internet IP Protocol */ 9 | #define AF_AX25 3 /* Amateur Radio AX.25 */ 10 | #define AF_IPX 4 /* Novell IPX */ 11 | #define AF_APPLETALK 5 /* AppleTalk DDP */ 12 | #define AF_NETROM 6 /* Amateur Radio NET/ROM */ 13 | #define AF_BRIDGE 7 /* Multiprotocol bridge */ 14 | #define AF_ATMPVC 8 /* ATM PVCs */ 15 | #define AF_X25 9 /* Reserved for X.25 project */ 16 | #define AF_INET6 10 /* IP version 6 */ 17 | #define AF_ROSE 11 /* Amateur Radio X.25 PLP */ 18 | #define AF_DECnet 12 /* Reserved for DECnet project */ 19 | #define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ 20 | #define AF_SECURITY 14 /* Security callback pseudo AF */ 21 | #define AF_KEY 15 /* PF_KEY key management API */ 22 | #define AF_NETLINK 16 23 | #define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */ 24 | #define AF_PACKET 17 /* Packet family */ 25 | #define AF_ASH 18 /* Ash */ 26 | #define AF_ECONET 19 /* Acorn Econet */ 27 | #define AF_ATMSVC 20 /* ATM SVCs */ 28 | #define AF_RDS 21 /* RDS sockets */ 29 | #define AF_SNA 22 /* Linux SNA Project (nutters!) */ 30 | #define AF_IRDA 23 /* IRDA sockets */ 31 | #define AF_PPPOX 24 /* PPPoX sockets */ 32 | #define AF_WANPIPE 25 /* Wanpipe API Sockets */ 33 | #define AF_LLC 26 /* Linux LLC */ 34 | #define AF_IB 27 /* Native InfiniBand address */ 35 | #define AF_MPLS 28 /* MPLS */ 36 | #define AF_CAN 29 /* Controller Area Network */ 37 | #define AF_TIPC 30 /* TIPC sockets */ 38 | #define AF_BLUETOOTH 31 /* Bluetooth sockets */ 39 | #define AF_IUCV 32 /* IUCV sockets */ 40 | #define AF_RXRPC 33 /* RxRPC sockets */ 41 | #define AF_ISDN 34 /* mISDN sockets */ 42 | #define AF_PHONET 35 /* Phonet sockets */ 43 | #define AF_IEEE802154 36 /* IEEE802154 sockets */ 44 | #define AF_CAIF 37 /* CAIF sockets */ 45 | #define AF_ALG 38 /* Algorithm sockets */ 46 | #define AF_NFC 39 /* NFC sockets */ 47 | #define AF_VSOCK 40 /* vSockets */ 48 | #define AF_KCM 41 /* Kernel Connection Multiplexor*/ 49 | #define AF_QIPCRTR 42 /* Qualcomm IPC Router */ 50 | #define AF_SMC 43 /* smc sockets: reserve number for 51 | * PF_SMC protocol family that 52 | * reuses AF_INET address family 53 | */ 54 | #define AF_XDP 44 /* XDP sockets */ 55 | 56 | #define AF_MAX 45 /* For now.. */ 57 | 58 | /* Protocol families, same as address families. */ 59 | #define PF_UNSPEC AF_UNSPEC 60 | #define PF_UNIX AF_UNIX 61 | #define PF_LOCAL AF_LOCAL 62 | #define PF_INET AF_INET 63 | #define PF_AX25 AF_AX25 64 | #define PF_IPX AF_IPX 65 | #define PF_APPLETALK AF_APPLETALK 66 | #define PF_NETROM AF_NETROM 67 | #define PF_BRIDGE AF_BRIDGE 68 | #define PF_ATMPVC AF_ATMPVC 69 | #define PF_X25 AF_X25 70 | #define PF_INET6 AF_INET6 71 | #define PF_ROSE AF_ROSE 72 | #define PF_DECnet AF_DECnet 73 | #define PF_NETBEUI AF_NETBEUI 74 | #define PF_SECURITY AF_SECURITY 75 | #define PF_KEY AF_KEY 76 | #define PF_NETLINK AF_NETLINK 77 | #define PF_ROUTE AF_ROUTE 78 | #define PF_PACKET AF_PACKET 79 | #define PF_ASH AF_ASH 80 | #define PF_ECONET AF_ECONET 81 | #define PF_ATMSVC AF_ATMSVC 82 | #define PF_RDS AF_RDS 83 | #define PF_SNA AF_SNA 84 | #define PF_IRDA AF_IRDA 85 | #define PF_PPPOX AF_PPPOX 86 | #define PF_WANPIPE AF_WANPIPE 87 | #define PF_LLC AF_LLC 88 | #define PF_IB AF_IB 89 | #define PF_MPLS AF_MPLS 90 | #define PF_CAN AF_CAN 91 | #define PF_TIPC AF_TIPC 92 | #define PF_BLUETOOTH AF_BLUETOOTH 93 | #define PF_IUCV AF_IUCV 94 | #define PF_RXRPC AF_RXRPC 95 | #define PF_ISDN AF_ISDN 96 | #define PF_PHONET AF_PHONET 97 | #define PF_IEEE802154 AF_IEEE802154 98 | #define PF_CAIF AF_CAIF 99 | #define PF_ALG AF_ALG 100 | #define PF_NFC AF_NFC 101 | #define PF_VSOCK AF_VSOCK 102 | #define PF_KCM AF_KCM 103 | #define PF_QIPCRTR AF_QIPCRTR 104 | #define PF_SMC AF_SMC 105 | #define PF_XDP AF_XDP 106 | #define PF_MAX AF_MAX 107 | 108 | /* Maximum queue length specifiable by listen. */ 109 | #define SOMAXCONN 4096 110 | 111 | /* Flags we can use with send/ and recv. 112 | Added those for 1003.1g not all are supported yet 113 | */ 114 | 115 | #define MSG_OOB 1 116 | #define MSG_PEEK 2 117 | #define MSG_DONTROUTE 4 118 | #define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */ 119 | #define MSG_CTRUNC 8 120 | #define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */ 121 | #define MSG_TRUNC 0x20 122 | #define MSG_DONTWAIT 0x40 /* Nonblocking io */ 123 | #define MSG_EOR 0x80 /* End of record */ 124 | #define MSG_WAITALL 0x100 /* Wait for a full request */ 125 | #define MSG_FIN 0x200 126 | #define MSG_SYN 0x400 127 | #define MSG_CONFIRM 0x800 /* Confirm path validity */ 128 | #define MSG_RST 0x1000 129 | #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ 130 | #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ 131 | #define MSG_MORE 0x8000 /* Sender will send more */ 132 | #define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ 133 | #define MSG_SENDPAGE_NOPOLICY 0x10000 /* sendpage() internal : do no apply policy */ 134 | #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ 135 | #define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ 136 | #define MSG_EOF MSG_FIN 137 | #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */ 138 | #define MSG_SENDPAGE_DECRYPTED 0x100000 /* sendpage() internal : page may carry 139 | * plain text and require encryption 140 | */ 141 | 142 | #define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */ 143 | #define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ 144 | #define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exec for file 145 | descriptor received through 146 | SCM_RIGHTS */ 147 | #if defined(CONFIG_COMPAT) 148 | #define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ 149 | #else 150 | #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ 151 | #endif 152 | 153 | 154 | /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ 155 | #define SOL_IP 0 156 | /* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */ 157 | #define SOL_TCP 6 158 | #define SOL_UDP 17 159 | #define SOL_IPV6 41 160 | #define SOL_ICMPV6 58 161 | #define SOL_SCTP 132 162 | #define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ 163 | #define SOL_RAW 255 164 | #define SOL_IPX 256 165 | #define SOL_AX25 257 166 | #define SOL_ATALK 258 167 | #define SOL_NETROM 259 168 | #define SOL_ROSE 260 169 | #define SOL_DECNET 261 170 | #define SOL_X25 262 171 | #define SOL_PACKET 263 172 | #define SOL_ATM 264 /* ATM layer (cell level) */ 173 | #define SOL_AAL 265 /* ATM Adaption Layer (packet level) */ 174 | #define SOL_IRDA 266 175 | #define SOL_NETBEUI 267 176 | #define SOL_LLC 268 177 | #define SOL_DCCP 269 178 | #define SOL_NETLINK 270 179 | #define SOL_TIPC 271 180 | #define SOL_RXRPC 272 181 | #define SOL_PPPOL2TP 273 182 | #define SOL_BLUETOOTH 274 183 | #define SOL_PNPIPE 275 184 | #define SOL_RDS 276 185 | #define SOL_IUCV 277 186 | #define SOL_CAIF 278 187 | #define SOL_ALG 279 188 | #define SOL_NFC 280 189 | #define SOL_KCM 281 190 | #define SOL_TLS 282 191 | #define SOL_XDP 283 192 | 193 | /* IPX options */ 194 | #define IPX_TYPE 1 195 | 196 | #endif -------------------------------------------------------------------------------- /bpf/headers/upai_in6_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef __UAPI_DEF_IPPROTO_V6 2 | #define __UAPI_DEF_IPPROTO_V6 1 3 | 4 | #define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ 5 | #define IPPROTO_ROUTING 43 /* IPv6 routing header */ 6 | #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ 7 | #define IPPROTO_ICMPV6 58 /* ICMPv6 */ 8 | #define IPPROTO_NONE 59 /* IPv6 no next header */ 9 | #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ 10 | #define IPPROTO_MH 135 /* IPv6 mobility header */ 11 | 12 | #endif /* __UAPI_DEF_IPPROTO_V6 */ 13 | -------------------------------------------------------------------------------- /bpf/headers/vmlinux.h: -------------------------------------------------------------------------------- 1 | #if defined(__TARGET_ARCH_x86) 2 | #include "vmlinux-x86.h" 3 | #elif defined(__TARGET_ARCH_arm64) 4 | #include "vmlinux-arm64.h" 5 | #elif defined(__TARGET_ARCH_riscv) 6 | #include "vmlinux-riscv.h" 7 | #else 8 | /* 9 | * For other architectures, we don't have a vmlinux.h file. But the normal dae 10 | * bpf program doesn't need it. So we just include the x86 vmlinux.h file to 11 | * make the build pass. 12 | */ 13 | #include "vmlinux-x86.h" 14 | #endif 15 | -------------------------------------------------------------------------------- /bpf/ktcpdump.c: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 3 | 4 | #include "vmlinux.h" 5 | #include "bpf_helpers.h" 6 | #include "bpf_tracing.h" 7 | #include "bpf_core_read.h" 8 | 9 | #define MAX_STACK_DEPTH 50 10 | #define MAX_DATA_SIZE 9000 11 | #define MAX_TRACK_SIZE 10240 12 | 13 | const static u32 ZERO = 0; 14 | const static u8 TRUE = 1; 15 | 16 | struct event { 17 | u64 at; 18 | u64 ts; 19 | u64 skb; 20 | u64 call; 21 | u32 data_len; 22 | u16 protocol; 23 | u8 has_mac; 24 | u8 dev[16]; 25 | }; 26 | 27 | const struct event *_ __attribute__((unused)); 28 | 29 | struct skb_data { 30 | u8 data[MAX_DATA_SIZE]; 31 | }; 32 | 33 | struct { 34 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 35 | __type(key, u32); 36 | __type(value, u8[MAX_DATA_SIZE + sizeof(struct event)]); 37 | __uint(max_entries, 1); 38 | } ringbuf_data SEC(".maps"); 39 | 40 | struct { 41 | __uint(type, BPF_MAP_TYPE_LRU_HASH); 42 | __type(key, struct sk_buff *); 43 | __type(value, u8); 44 | __uint(max_entries, MAX_TRACK_SIZE); 45 | } alive_skbs SEC(".maps"); 46 | 47 | struct { 48 | __uint(type, BPF_MAP_TYPE_RINGBUF); 49 | __uint(max_entries, 1<<29); 50 | } event_ringbuf SEC(".maps"); 51 | 52 | #define is_skb_on_reg(r) \ 53 | reg = BPF_CORE_READ(ctx, r); \ 54 | if (reg && bpf_map_lookup_elem(&alive_skbs, ®)) \ 55 | return reg; 56 | 57 | static __always_inline u64 search_skb_from_register(struct pt_regs *ctx) 58 | { 59 | u64 reg = 0; 60 | is_skb_on_reg(r15); 61 | is_skb_on_reg(r14); 62 | is_skb_on_reg(r13); 63 | is_skb_on_reg(r12); 64 | is_skb_on_reg(bp); 65 | is_skb_on_reg(bx); 66 | is_skb_on_reg(r11); 67 | is_skb_on_reg(r10); 68 | is_skb_on_reg(r9); 69 | is_skb_on_reg(r8); 70 | is_skb_on_reg(ax); 71 | is_skb_on_reg(cx); 72 | is_skb_on_reg(dx); 73 | is_skb_on_reg(si); 74 | is_skb_on_reg(di); 75 | return 0; 76 | } 77 | 78 | static __always_inline u64 search_skb_from_stack(struct pt_regs *ctx) 79 | { 80 | u64 sp = (u64)PT_REGS_SP(ctx); 81 | 82 | u64 maybe_skb; 83 | for (int i = 0; i < MAX_STACK_DEPTH; i++) { 84 | u64 addr = sp + i * sizeof(u64); 85 | bpf_probe_read_kernel(&maybe_skb, sizeof(maybe_skb), (void *)addr); 86 | if (bpf_map_lookup_elem(&alive_skbs, &maybe_skb)) 87 | return maybe_skb; 88 | } 89 | 90 | return 0; 91 | } 92 | 93 | static __noinline bool 94 | kprobe_pcap_filter_l3(void *_skb, void *__skb, void *___skb, void *data, void* data_end) 95 | { 96 | return data != data_end && _skb == __skb && __skb == ___skb; 97 | } 98 | 99 | static __noinline bool 100 | kprobe_pcap_filter_l2(void *_skb, void *__skb, void *___skb, void *data, void* data_end) 101 | { 102 | return data != data_end && _skb == __skb && __skb == ___skb; 103 | } 104 | 105 | static __always_inline bool 106 | kprobe_pcap_filter(struct sk_buff *skb, u8 *has_mac, u16 *off_l2_or_l3) 107 | { 108 | void *skb_head = BPF_CORE_READ(skb, head); 109 | void *data_end = skb_head + BPF_CORE_READ(skb, tail); 110 | 111 | u16 mac_header = BPF_CORE_READ(skb, mac_header); 112 | u16 network_header = BPF_CORE_READ(skb, network_header); 113 | *has_mac = BPF_CORE_READ(skb, dev, hard_header_len) && mac_header < network_header ? 1 : 0; 114 | *off_l2_or_l3 = *has_mac ? mac_header : network_header; 115 | 116 | if (!*has_mac) { 117 | void *data = skb_head + BPF_CORE_READ(skb, network_header); 118 | return kprobe_pcap_filter_l3((void *)skb, (void *)skb, (void *)skb, 119 | data, data_end); 120 | } 121 | 122 | void *data = skb_head + BPF_CORE_READ(skb, mac_header); 123 | return kprobe_pcap_filter_l2((void *)skb, (void *)skb, (void *)skb, 124 | data, data_end); 125 | } 126 | 127 | static __always_inline void 128 | get_call_target(struct pt_regs *ctx, u64 *call, u64 cookie) 129 | { 130 | switch (cookie) { 131 | case 1: 132 | BPF_CORE_READ_INTO(call, ctx, r15); 133 | break; 134 | case 2: 135 | BPF_CORE_READ_INTO(call, ctx, r14); 136 | break; 137 | case 3: 138 | BPF_CORE_READ_INTO(call, ctx, r13); 139 | break; 140 | case 4: 141 | BPF_CORE_READ_INTO(call, ctx, r12); 142 | break; 143 | case 5: 144 | BPF_CORE_READ_INTO(call, ctx, bp); 145 | break; 146 | case 6: 147 | BPF_CORE_READ_INTO(call, ctx, bx); 148 | break; 149 | case 7: 150 | BPF_CORE_READ_INTO(call, ctx, r11); 151 | break; 152 | case 8: 153 | BPF_CORE_READ_INTO(call, ctx, r10); 154 | break; 155 | case 9: 156 | BPF_CORE_READ_INTO(call, ctx, r9); 157 | break; 158 | case 10: 159 | BPF_CORE_READ_INTO(call, ctx, r8); 160 | break; 161 | case 11: 162 | BPF_CORE_READ_INTO(call, ctx, ax); 163 | break; 164 | case 12: 165 | BPF_CORE_READ_INTO(call, ctx, cx); 166 | break; 167 | case 13: 168 | BPF_CORE_READ_INTO(call, ctx, dx); 169 | break; 170 | case 14: 171 | BPF_CORE_READ_INTO(call, ctx, si); 172 | break; 173 | case 15: 174 | BPF_CORE_READ_INTO(call, ctx, di); 175 | break; 176 | default: 177 | *call = 0; 178 | } 179 | } 180 | 181 | SEC("kprobe/skb_by_search") 182 | int kprobe_skb_by_search(struct pt_regs *ctx) 183 | { 184 | struct sk_buff *skb; 185 | 186 | skb = (struct sk_buff *)search_skb_from_register(ctx); 187 | if (!skb) 188 | skb = (struct sk_buff *)search_skb_from_stack(ctx); 189 | if (!skb) 190 | return BPF_OK; 191 | 192 | u8 has_mac; 193 | u16 off_l2_or_l3; 194 | if (!kprobe_pcap_filter(skb, &has_mac, &off_l2_or_l3)) 195 | return BPF_OK; 196 | 197 | void *ringbuf = bpf_map_lookup_elem(&ringbuf_data, &ZERO); 198 | if (!ringbuf) 199 | return BPF_OK; 200 | 201 | struct event *event = (struct event *)ringbuf; 202 | 203 | event->at = PT_REGS_IP(ctx); 204 | event->ts = bpf_ktime_get_boot_ns(); 205 | event->skb = (u64)skb; 206 | event->has_mac = has_mac; 207 | event->protocol = BPF_CORE_READ(skb, protocol); 208 | BPF_CORE_READ_STR_INTO(&event->dev, skb, dev, name); 209 | get_call_target(ctx, &event->call, bpf_get_attach_cookie(ctx)); 210 | 211 | event->data_len = BPF_CORE_READ(skb, tail) - (u32)off_l2_or_l3; 212 | event->data_len = event->data_len > MAX_DATA_SIZE 213 | ? MAX_DATA_SIZE 214 | : event->data_len; 215 | 216 | u32 data_len = event->data_len; 217 | 218 | struct skb_data *skb_data = (struct skb_data *)(event + 1); 219 | 220 | void *skb_head = BPF_CORE_READ(skb, head); 221 | 222 | bpf_probe_read_kernel(&skb_data->data, data_len, (void *)(skb_head + off_l2_or_l3)); 223 | bpf_ringbuf_output(&event_ringbuf, ringbuf, sizeof(*event) + data_len, 0); 224 | 225 | return BPF_OK; 226 | } 227 | 228 | SEC("kretprobe/skb_build") 229 | int kretprobe_skb_build(struct pt_regs *ctx) 230 | { 231 | struct sk_buff *skb = (struct sk_buff *)PT_REGS_RC(ctx); 232 | bpf_map_update_elem(&alive_skbs, &skb, &TRUE, BPF_ANY); 233 | return BPF_OK; 234 | } 235 | 236 | SEC("kprobe/skb_free") 237 | int kprobe_skb_free(struct pt_regs *ctx) 238 | { 239 | struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx); 240 | bpf_map_delete_elem(&alive_skbs, &skb); 241 | 242 | return BPF_OK; 243 | } 244 | 245 | char __license[] SEC("license") = "Dual BSD/GPL"; 246 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | log "log/slog" 6 | "os" 7 | "strings" 8 | 9 | "github.com/spf13/pflag" 10 | ) 11 | 12 | type Config struct { 13 | Pcapfilter string 14 | Targets []string 15 | PcapFilename string 16 | Verbose bool 17 | DbgImagePath string 18 | } 19 | 20 | var config Config 21 | 22 | func init() { 23 | var help bool 24 | pflag.BoolVarP(&help, "help", "h", false, "") 25 | pflag.StringSliceVarP(&config.Targets, "i", "i", []string{"__netif_receive_skb_core", "__dev_queue_xmit"}, "symbol|symbol+offset|address") 26 | pflag.StringVarP(&config.PcapFilename, "w", "w", "/tmp/a.pcap", "write packets to a file") 27 | pflag.BoolVarP(&config.Verbose, "v", "v", false, "verbose output") 28 | pflag.StringVarP(&config.DbgImagePath, "d", "d", "", "path to debug image") 29 | pflag.Parse() 30 | 31 | config.Pcapfilter = strings.Join(pflag.Args(), " ") 32 | 33 | if help || len(config.Pcapfilter) == 0 { 34 | fmt.Fprintf(os.Stderr, "ktcpdump [ -i kfunc ] [ -w file ] [ -d vmlinux-dbg ] [ -v ] expresssion\n") 35 | pflag.PrintDefaults() 36 | os.Exit(1) 37 | } 38 | 39 | if config.Verbose { 40 | log.SetDefault(log.New(log.NewTextHandler(os.Stdout, &log.HandlerOptions{Level: log.LevelDebug}))) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jschwinger233/ktcpdump 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/cilium/ebpf v0.16.0 7 | github.com/elastic/go-sysinfo v1.15.0 8 | github.com/google/gopacket v1.1.19 9 | github.com/jschwinger233/elibpcap v1.0.0 10 | github.com/spf13/pflag v1.0.5 11 | golang.org/x/arch v0.12.0 12 | ) 13 | 14 | require ( 15 | github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff // indirect 16 | github.com/elastic/go-windows v1.0.0 // indirect 17 | github.com/pkg/errors v0.9.1 // indirect 18 | github.com/prometheus/procfs v0.15.1 // indirect 19 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect 20 | golang.org/x/net v0.23.0 // indirect 21 | golang.org/x/sys v0.25.0 // indirect 22 | howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= 2 | github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= 3 | github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff h1:SLLG1soGN/PYTXkYWiR1PAxWlP1URBvgZPYymC5+0WI= 4 | github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff/go.mod h1:1xLQNNpgw8yNlVjGrtUHBx0KL52fif71sKa1PleulAQ= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/elastic/go-sysinfo v1.15.0 h1:54pRFlAYUlVNQ2HbXzLVZlV+fxS7Eax49stzg95M4Xw= 9 | github.com/elastic/go-sysinfo v1.15.0/go.mod h1:jPSuTgXG+dhhh0GKIyI2Cso+w5lPJ5PvVqKlL8LV/Hk= 10 | github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= 11 | github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= 12 | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 13 | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 14 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 15 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 16 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 17 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 18 | github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= 19 | github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= 20 | github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= 21 | github.com/jschwinger233/elibpcap v1.0.0 h1:UQuP3XT9orz26lW6DPTu9B9OBYirB57LmhPNGxQqU2U= 22 | github.com/jschwinger233/elibpcap v1.0.0/go.mod h1:fUmq00C6Pechtr089JDPhvIc6TxrbUHDlZ5QCYc9tJQ= 23 | github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= 24 | github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= 25 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 26 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 27 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 28 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 29 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 30 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 31 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 32 | github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= 33 | github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= 34 | github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= 35 | github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= 36 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 37 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 38 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 39 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 40 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 41 | github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= 42 | github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= 43 | github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= 44 | github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 45 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 46 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 47 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 48 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 49 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 50 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 51 | golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= 52 | golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 53 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 54 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 55 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= 56 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 57 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 58 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 59 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 60 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 61 | golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= 62 | golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 63 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 64 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 65 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 66 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 67 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 68 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= 69 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 70 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 71 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 72 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 73 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 74 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 75 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 76 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 77 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 78 | howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= 79 | howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= 80 | -------------------------------------------------------------------------------- /kcore.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/elf" 5 | "fmt" 6 | log "log/slog" 7 | "os" 8 | "sync" 9 | 10 | "golang.org/x/arch/x86/x86asm" 11 | ) 12 | 13 | const ( 14 | kcorePath string = "/proc/kcore" 15 | ) 16 | 17 | var ( 18 | kcoreOnce sync.Once 19 | kcore *Kcore 20 | ) 21 | 22 | type Kcore struct { 23 | path string 24 | file *os.File 25 | elf *elf.File 26 | } 27 | 28 | type Instruction struct { 29 | Symbol string 30 | Offset uint64 31 | Call bool 32 | CallTarget string 33 | *LineInfo 34 | } 35 | 36 | func NewKcore() (*Kcore, error) { 37 | file, err := os.Open(kcorePath) 38 | if err != nil { 39 | return nil, fmt.Errorf("failed to open kcore: %w", err) 40 | } 41 | elf, err := elf.NewFile(file) 42 | if err != nil { 43 | return nil, fmt.Errorf("failed to open kcore: %w", err) 44 | } 45 | return &Kcore{ 46 | path: kcorePath, 47 | file: file, 48 | elf: elf, 49 | }, nil 50 | } 51 | 52 | func GetKcore() (_ *Kcore, err error) { 53 | kcoreOnce.Do(func() { 54 | kcore, err = NewKcore() 55 | }) 56 | return kcore, err 57 | } 58 | 59 | func (k *Kcore) ParseInsns(symbol string) (insns map[uint64]*Instruction, err error) { 60 | insns = make(map[uint64]*Instruction) 61 | kdwarf, err := GetKdwarf() 62 | if err != nil { 63 | log.Debug("Failed to get kdwarf", "err", err) 64 | } 65 | 66 | ksym, err := KsymByName(symbol) 67 | if err != nil { 68 | return 69 | } 70 | addr := ksym.Addr 71 | this, next := NearestKsym(addr) 72 | leng := next.Addr - this.Addr 73 | 74 | for _, prog := range k.elf.Progs { 75 | if prog.Vaddr <= addr && prog.Vaddr+prog.Memsz >= addr { 76 | bytes := make([]byte, leng) 77 | if _, err = k.file.ReadAt(bytes, int64(prog.Off+addr-prog.Vaddr)); err != nil { 78 | log.Debug("Failed to read kcore", "err", err) 79 | continue 80 | } 81 | if len(bytes) == 0 { 82 | continue 83 | } 84 | off := 0 85 | for { 86 | inst, err := x86asm.Decode(bytes, 64) 87 | if err != nil { 88 | inst = x86asm.Inst{Len: 1} 89 | off += 1 90 | } else { 91 | insn := Instruction{ 92 | Symbol: symbol, 93 | Offset: uint64(off), 94 | } 95 | if inst.Op == x86asm.CALL { 96 | insn.Call = true 97 | for _, arg := range inst.Args { 98 | if arg == nil { 99 | break 100 | } 101 | rel, ok := arg.(x86asm.Rel) 102 | if !ok { 103 | reg, ok := arg.(x86asm.Reg) 104 | if ok { 105 | insn.CallTarget = reg.String() 106 | break 107 | } 108 | } 109 | callee := addr + uint64(off) + uint64(rel) + uint64(inst.Len) 110 | ksym, err := KsymByAddr(callee) 111 | if err == nil { 112 | insn.CallTarget = ksym.Name 113 | } 114 | break 115 | } 116 | } 117 | if kdwarf != nil { 118 | insn.LineInfo, _ = kdwarf.GetLineInfo(symbol, uint64(off)) 119 | } 120 | insns[uint64(off)] = &insn 121 | } 122 | 123 | bytes = bytes[inst.Len:] 124 | off += inst.Len 125 | if len(bytes) == 0 { 126 | break 127 | } 128 | } 129 | } 130 | } 131 | 132 | return 133 | } 134 | -------------------------------------------------------------------------------- /kdwarf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/dwarf" 5 | "debug/elf" 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | var ( 11 | kdwarfOnce sync.Once 12 | kdwarf *Kdwarf 13 | ) 14 | 15 | type LineInfo struct { 16 | Filename string 17 | Line int 18 | } 19 | 20 | type Kdwarf struct { 21 | path string 22 | file *elf.File 23 | dwarfData *dwarf.Data 24 | 25 | lineInfos map[uint64]*LineInfo 26 | symbols map[string]uint64 27 | } 28 | 29 | func NewKdwarf(path string) (*Kdwarf, error) { 30 | file, err := elf.Open(path) 31 | if err != nil { 32 | return nil, fmt.Errorf("failed to open ELF file: %w", err) 33 | } 34 | 35 | dwarfData, err := file.DWARF() 36 | if err != nil { 37 | file.Close() 38 | return nil, fmt.Errorf("failed to get DWARF data: %w", err) 39 | } 40 | 41 | kdwarf := &Kdwarf{ 42 | file: file, 43 | path: path, 44 | dwarfData: dwarfData, 45 | symbols: make(map[string]uint64), 46 | lineInfos: make(map[uint64]*LineInfo), 47 | } 48 | if err := kdwarf.parseSymbols(); err != nil { 49 | return nil, err 50 | } 51 | return kdwarf, kdwarf.parseLineInfos() 52 | } 53 | 54 | func GetKdwarf() (_ *Kdwarf, err error) { 55 | if config.DbgImagePath == "" { 56 | return nil, fmt.Errorf("-d vmlinux-dbg is required") 57 | } 58 | kdwarfOnce.Do(func() { 59 | kdwarf, err = NewKdwarf(config.DbgImagePath) 60 | }) 61 | return kdwarf, err 62 | } 63 | 64 | func (p *Kdwarf) parseSymbols() (err error) { 65 | symbolTable, err := p.file.Symbols() 66 | if err != nil { 67 | return 68 | } 69 | 70 | for _, sym := range symbolTable { 71 | if sym.Name != "" { 72 | p.symbols[sym.Name] = sym.Value 73 | } 74 | } 75 | return nil 76 | } 77 | 78 | func (p *Kdwarf) parseLineInfos() (err error) { 79 | reader := p.dwarfData.Reader() 80 | for { 81 | entry, err := reader.Next() 82 | if err != nil { 83 | return fmt.Errorf("error reading DWARF entry: %w", err) 84 | } 85 | if entry == nil { 86 | break 87 | } 88 | 89 | if entry.Tag == dwarf.TagCompileUnit { 90 | lineReader, err := p.dwarfData.LineReader(entry) 91 | if err != nil { 92 | return fmt.Errorf("failed to get line reader: %w", err) 93 | } 94 | 95 | var lineEntry dwarf.LineEntry 96 | for { 97 | err := lineReader.Next(&lineEntry) 98 | if err == dwarf.ErrUnknownPC { 99 | continue 100 | } 101 | if err != nil { 102 | break 103 | } 104 | 105 | info := &LineInfo{ 106 | Filename: lineEntry.File.Name, 107 | Line: lineEntry.Line, 108 | } 109 | p.lineInfos[lineEntry.Address] = info 110 | 111 | } 112 | } 113 | } 114 | return 115 | } 116 | 117 | func (p *Kdwarf) GetLineInfo(symbol string, offset uint64) (*LineInfo, error) { 118 | address, found := p.symbols[symbol] 119 | if !found { 120 | return nil, fmt.Errorf("symbol %s not found in DWARF data", symbol) 121 | } 122 | 123 | address += offset 124 | 125 | if lineInfo, found := p.lineInfos[address]; found { 126 | return lineInfo, nil 127 | } 128 | return nil, fmt.Errorf("address 0x%x not found in DWARF data", address) 129 | } 130 | -------------------------------------------------------------------------------- /ksym.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "log" 7 | "os" 8 | "slices" 9 | "sort" 10 | "strconv" 11 | "strings" 12 | ) 13 | 14 | type Symbol struct { 15 | Type string 16 | Name string 17 | Addr uint64 18 | AvailableFilter bool 19 | } 20 | 21 | const ( 22 | kallsymsPath = "/proc/kallsyms" 23 | availableFilterFunctionsPath = "/sys/kernel/debug/tracing/available_filter_functions" 24 | ) 25 | 26 | var ( 27 | kallsyms []*Symbol 28 | kallsymsByName map[string]*Symbol = make(map[string]*Symbol) 29 | kallsymsByAddr map[uint64]*Symbol = make(map[uint64]*Symbol) 30 | availableFilterFuncs map[string]struct{} = make(map[string]struct{}) 31 | ) 32 | 33 | func init() { 34 | readKallsyms() 35 | readAvailableFilterFunctions() 36 | 37 | for _, sym := range kallsyms { 38 | if _, ok := availableFilterFuncs[sym.Name]; ok { 39 | sym.AvailableFilter = true 40 | } 41 | } 42 | } 43 | 44 | func readKallsyms() { 45 | data, err := os.ReadFile(kallsymsPath) 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | for _, line := range strings.Split(string(data), "\n") { 50 | parts := strings.Fields(line) 51 | if len(parts) < 3 { 52 | continue 53 | } 54 | addr, err := strconv.ParseUint(parts[0], 16, 64) 55 | if err != nil { 56 | continue 57 | } 58 | typ, name := parts[1], parts[2] 59 | symbol := &Symbol{typ, name, addr, false} 60 | kallsyms = append(kallsyms, symbol) 61 | kallsymsByName[name] = symbol 62 | kallsymsByAddr[addr] = symbol 63 | } 64 | sort.Slice(kallsyms, func(i, j int) bool { 65 | return kallsyms[i].Addr < kallsyms[j].Addr 66 | }) 67 | } 68 | 69 | func readAvailableFilterFunctions() { 70 | f, err := os.Open(availableFilterFunctionsPath) 71 | if err != nil { 72 | log.Fatalf("Failed to open available_filter_functions: %s\n", err) 73 | } 74 | defer f.Close() 75 | 76 | scanner := bufio.NewScanner(f) 77 | scanner.Split(bufio.ScanLines) 78 | for scanner.Scan() { 79 | availableFilterFuncs[scanner.Text()] = struct{}{} 80 | } 81 | if err := scanner.Err(); err != nil { 82 | log.Fatalf("Failed to read available_filter_functions: %s\n", err) 83 | } 84 | } 85 | 86 | func NearestKsym(addr uint64) (this, next *Symbol) { 87 | idx, _ := slices.BinarySearchFunc(kallsyms, addr, func(x *Symbol, addr uint64) int { return int(x.Addr - addr) }) 88 | if idx == len(kallsyms) { 89 | return kallsyms[idx-1], nil 90 | } 91 | if kallsyms[idx].Addr == addr { 92 | return kallsyms[idx], kallsyms[idx+1] 93 | } 94 | if idx == 0 { 95 | return kallsyms[0], kallsyms[1] 96 | } 97 | return kallsyms[idx-1], kallsyms[idx] 98 | } 99 | 100 | func KsymByAddr(addr uint64) (sym *Symbol, err error) { 101 | sym, ok := kallsymsByAddr[addr] 102 | if !ok { 103 | return nil, errors.New("symbol not found") 104 | } 105 | return sym, nil 106 | } 107 | 108 | func KsymByName(name string) (sym *Symbol, err error) { 109 | name, err = normalizeKname(name) 110 | if err != nil { 111 | return 112 | } 113 | return kallsymsByName[name], nil 114 | } 115 | 116 | func normalizeKname(name string) (string, error) { 117 | possibleSuffixes := []string{ 118 | "", 119 | ".cold", 120 | ".constprop.0", 121 | ".constprop.0.cold", 122 | ".constprop.0.isra.0", 123 | ".constprop.0.isra.0.cold", 124 | ".isra.0", 125 | ".isra.0.cold", 126 | ".part.0", 127 | ".part.0.cold", 128 | ".part.0.constprop.0", 129 | ".part.0.isra.0", 130 | ".part.0.isra.0.cold", 131 | } 132 | for _, suffix := range possibleSuffixes { 133 | if _, ok := kallsymsByName[name+suffix]; ok { 134 | return name + suffix, nil 135 | } 136 | } 137 | return "", errors.New("symbol not found") 138 | } 139 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/binary" 7 | "errors" 8 | "fmt" 9 | 10 | log "log/slog" 11 | "os" 12 | "os/signal" 13 | "regexp" 14 | "strings" 15 | "time" 16 | 17 | "github.com/cilium/ebpf" 18 | "github.com/cilium/ebpf/btf" 19 | "github.com/cilium/ebpf/link" 20 | "github.com/cilium/ebpf/ringbuf" 21 | "github.com/elastic/go-sysinfo" 22 | "github.com/google/gopacket" 23 | "github.com/google/gopacket/layers" 24 | "github.com/google/gopacket/pcapgo" 25 | "github.com/jschwinger233/elibpcap" 26 | "github.com/jschwinger233/ktcpdump/bpf" 27 | ) 28 | 29 | var targetPattern *regexp.Regexp 30 | 31 | func init() { 32 | targetPattern = regexp.MustCompile(`(?P[^+]*)(?:\+(?P.+))?`) 33 | } 34 | 35 | func main() { 36 | spec, err := bpf.LoadBpf() 37 | if err != nil { 38 | log.Error("Failed to load BPF", "err", err) 39 | return 40 | } 41 | 42 | prog, ok := spec.Programs["kprobe_skb_by_search"] 43 | if !ok { 44 | log.Error("Failed to find kprobe_skb_by_search") 45 | return 46 | } 47 | if prog.Instructions, err = elibpcap.Inject( 48 | config.Pcapfilter, 49 | prog.Instructions, 50 | elibpcap.Options{ 51 | AtBpf2Bpf: "kprobe_pcap_filter_l2", 52 | DirectRead: false, 53 | L2Skb: true, 54 | }, 55 | ); err != nil { 56 | log.Error("Failed to inject kprobe_pcap_filter_l2", "err", err) 57 | return 58 | } 59 | if prog.Instructions, err = elibpcap.Inject( 60 | config.Pcapfilter, 61 | prog.Instructions, 62 | elibpcap.Options{ 63 | AtBpf2Bpf: "kprobe_pcap_filter_l3", 64 | DirectRead: false, 65 | L2Skb: false, 66 | }, 67 | ); err != nil && strings.Contains(fmt.Sprintf("%+v", err), "expression rejects all packets") { 68 | if prog.Instructions, err = elibpcap.Inject( 69 | "__reject_all__", 70 | prog.Instructions, 71 | elibpcap.Options{ 72 | AtBpf2Bpf: "kprobe_pcap_filter_l3", 73 | DirectRead: false, 74 | L2Skb: false, 75 | }, 76 | ); err != nil { 77 | log.Error("Failed to inject kprobe_pcap_filter_l3", "err", err) 78 | return 79 | } 80 | } 81 | 82 | var opts ebpf.CollectionOptions 83 | opts.Programs.LogLevel = ebpf.LogLevelInstruction 84 | opts.Programs.LogSize = ebpf.DefaultVerifierLogSize * 100 85 | objs := bpf.BpfObjects{} 86 | if err := spec.LoadAndAssign(&objs, &opts); err != nil { 87 | var ( 88 | ve *ebpf.VerifierError 89 | verifierLog string 90 | ) 91 | if errors.As(err, &ve) { 92 | verifierLog = fmt.Sprintf("Verifier error: %+v\n", ve) 93 | } 94 | 95 | log.Error(verifierLog, "err", err) 96 | return 97 | } 98 | 99 | k, err := link.Kprobe("kfree_skbmem", objs.KprobeSkbFree, nil) 100 | if err != nil { 101 | log.Error("Failed to attach kfree_skbmem", "err", err) 102 | return 103 | } 104 | defer k.Close() 105 | 106 | kdwarf, _ := GetKdwarf() 107 | allInsns := map[string]map[uint64]*Instruction{} 108 | for _, target := range config.Targets { 109 | match := targetPattern.FindStringSubmatch(target) 110 | result := make(map[string]string) 111 | for i, name := range targetPattern.SubexpNames() { 112 | if i != 0 && name != "" { 113 | result[name] = match[i] 114 | } 115 | } 116 | if result["sym"] != "" && result["addr"] == "" { 117 | _, ok := IsDigit(result["sym"]) 118 | if ok { 119 | result["addr"] = result["sym"] 120 | delete(result, "sym") 121 | } 122 | } 123 | 124 | var ok bool 125 | var err error 126 | var address uint64 127 | var attachByInsn bool 128 | if result["addr"] == "*" { 129 | attachByInsn = true 130 | delete(result, "addr") 131 | } 132 | if result["addr"] != "" { 133 | address, ok = IsDigit(result["addr"]) 134 | if !ok { 135 | log.Error("Invalid address", "addr", result["addr"]) 136 | return 137 | } 138 | } 139 | 140 | var symbol string 141 | var offset uint64 142 | if result["sym"] == "" && address == 0 { 143 | log.Error("Invalid target", "target", target) 144 | return 145 | } else if result["sym"] == "" && address != 0 { 146 | sym, _ := NearestKsym(address) 147 | symbol = sym.Name 148 | offset = sym.Addr - address 149 | } else if result["sym"] != "" && address == 0 { 150 | symbol = result["sym"] 151 | offset = 0 152 | } else { 153 | symbol = result["sym"] 154 | offset = address 155 | } 156 | ksym, err := KsymByName(symbol) 157 | if err != nil { 158 | log.Error("Failed to find ksym", "symbol", symbol, "err", err) 159 | return 160 | } 161 | symbol = ksym.Name 162 | 163 | if attachByInsn { 164 | kcore, err := NewKcore() 165 | if err != nil { 166 | log.Error("Failed to new kcore", "err", err) 167 | return 168 | } 169 | insns, err := kcore.ParseInsns(symbol) 170 | if err != nil { 171 | log.Error("Failed to find lines", "symbol", symbol, "err", err) 172 | return 173 | } 174 | allInsns[symbol] = insns 175 | 176 | for _, ins := range insns { 177 | cookie := RegisterToCookie(ins.CallTarget) 178 | log.Debug("Attaching", "symbol", ins.Symbol, "offset", ins.Offset, "cookie", cookie) 179 | k, err := link.Kprobe(symbol, objs.KprobeSkbBySearch, &link.KprobeOptions{Offset: ins.Offset, Cookie: cookie}) 180 | if err != nil { 181 | log.Debug("Failed to attach targets", "symbol", symbol, "offset", ins.Offset, "err", err) 182 | continue 183 | } 184 | defer k.Close() 185 | } 186 | 187 | } else { 188 | insns, ok := allInsns[symbol] 189 | if !ok { 190 | allInsns[symbol] = map[uint64]*Instruction{} 191 | insns = allInsns[symbol] 192 | } 193 | insns[offset] = &Instruction{ 194 | Symbol: symbol, 195 | Offset: offset, 196 | } 197 | if kdwarf != nil { 198 | insns[offset].LineInfo, _ = kdwarf.GetLineInfo(symbol, offset) 199 | } 200 | 201 | k, err = link.Kprobe(symbol, objs.KprobeSkbBySearch, &link.KprobeOptions{Offset: offset}) 202 | if err != nil { 203 | log.Error("Failed to attach", "target", target, "err", err) 204 | return 205 | } 206 | defer k.Close() 207 | } 208 | } 209 | 210 | skbBuildFuncs := []string{} 211 | btfSpec, err := btf.LoadKernelSpec() 212 | if err != nil { 213 | log.Error("Failed to load kernel BTF", "err", err) 214 | return 215 | } 216 | iter := btfSpec.Iterate() 217 | for iter.Next() { 218 | typ := iter.Type 219 | fn, ok := typ.(*btf.Func) 220 | if !ok { 221 | continue 222 | } 223 | fnProto := fn.Type.(*btf.FuncProto) 224 | if ptr, ok := fnProto.Return.(*btf.Pointer); ok { 225 | if strct, ok := ptr.Target.(*btf.Struct); ok { 226 | if strct.Name == "sk_buff" { 227 | skbBuildFuncs = append(skbBuildFuncs, fn.Name) 228 | continue 229 | } 230 | } 231 | } 232 | } 233 | for _, skbBuildFunc := range skbBuildFuncs { 234 | ksym, err := KsymByName(skbBuildFunc) 235 | if err != nil { 236 | log.Error("Failed to find ksym", "symbol", skbBuildFunc, "err", err) 237 | continue 238 | } 239 | log.Debug("Attaching", "symbol", ksym.Name) 240 | kr, err := link.Kretprobe(ksym.Name, objs.KretprobeSkbBuild, nil) 241 | if err != nil { 242 | log.Debug("Failed to attach skb build func", "symbol", ksym.Name, "err", err) 243 | continue 244 | } 245 | defer kr.Close() 246 | } 247 | 248 | eventsReader, err := ringbuf.NewReader(objs.EventRingbuf) 249 | if err != nil { 250 | log.Error("Failed to create ringbuf reader", "err", err) 251 | return 252 | } 253 | defer eventsReader.Close() 254 | 255 | ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) 256 | defer cancel() 257 | 258 | go func() { 259 | <-ctx.Done() 260 | eventsReader.Close() 261 | }() 262 | 263 | host, err := sysinfo.Host() 264 | if err != nil { 265 | log.Error("Failed to get host info", "err", err) 266 | return 267 | } 268 | bootTime := host.Info().BootTime 269 | 270 | f, err := os.Create(config.PcapFilename) 271 | if err != nil { 272 | log.Error("Failed to create pcap file", "err", err) 273 | return 274 | } 275 | defer f.Close() 276 | 277 | pcapw := pcapgo.NewWriter(f) 278 | linktype := layers.LinkTypeEthernet 279 | if err = pcapw.WriteFileHeader(1600, linktype); err != nil { 280 | log.Error("Failed to write pcap file header", "err", err) 281 | return 282 | } 283 | 284 | sizeofEvent := binary.Size(bpf.BpfEvent{}) 285 | 286 | fmt.Printf("%-4s %-16s %-16s %-18s %-16s\n", "no", "skb", "skb->dev->name", "pc", "ksym") 287 | i := 0 288 | 289 | for { 290 | i++ 291 | rec, err := eventsReader.Read() 292 | if err != nil { 293 | if errors.Is(err, ringbuf.ErrClosed) { 294 | return 295 | } 296 | log.Debug("failed to read ringbuf", "err", err) 297 | continue 298 | } 299 | 300 | var event bpf.BpfEvent 301 | if err = binary.Read(bytes.NewBuffer(rec.RawSample), binary.LittleEndian, &event); err != nil { 302 | log.Debug("failed to parse ringbuf event", "err", err) 303 | continue 304 | } 305 | 306 | if err != nil { 307 | log.Error("Failed to get dwarf", "err", err) 308 | return 309 | } 310 | ksym, _ := NearestKsym(event.At) 311 | 312 | var insn *Instruction 313 | insns, ok := allInsns[ksym.Name] 314 | if ok { 315 | insn, ok = insns[event.At-ksym.Addr-1] 316 | if !ok { 317 | insn, ok = insns[event.At-ksym.Addr-4] 318 | if !ok { 319 | log.Error("Failed to find insn", "symbol", ksym.Name, "offset", event.At-ksym.Addr) 320 | return 321 | } 322 | } 323 | } 324 | 325 | fmt.Printf("%-4d %-16x %-16s %-18x %-16s", i, event.Skb, strings.TrimRight(string(event.Dev[:]), "\x00"), event.At, fmt.Sprintf("%s+%d", ksym.Name, event.At-ksym.Addr)) 326 | if insn.LineInfo != nil { 327 | fmt.Printf(" %s:%d", insn.Filename, insn.Line) 328 | } 329 | if insn.Call { 330 | ksym, err := KsymByAddr(event.Call) 331 | if event.Call != 0 && err == nil { 332 | fmt.Printf(" // CALL %s", ksym.Name) 333 | } else { 334 | fmt.Printf(" // CALL %s", insn.CallTarget) 335 | } 336 | } 337 | fmt.Println() 338 | 339 | skbData := make([]byte, event.DataLen) 340 | 341 | if err = binary.Read(bytes.NewBuffer(rec.RawSample[sizeofEvent:]), binary.LittleEndian, &skbData); err != nil { 342 | log.Warn("failed to parse ringbuf skbdata", 343 | "skb", fmt.Sprintf("%x", event.Skb), 344 | "data_len", event.DataLen, 345 | "err", err) 346 | continue 347 | } 348 | 349 | captureInfo := gopacket.CaptureInfo{ 350 | Timestamp: bootTime.Add(time.Duration(event.Ts)), 351 | CaptureLength: int(event.DataLen), 352 | Length: int(event.DataLen), 353 | } 354 | payload := []byte{} 355 | 356 | if event.HasMac == 0 { 357 | for i := 0; i < 12; i++ { 358 | payload = append(payload, 0) 359 | } 360 | ethertype := make([]byte, 2) 361 | binary.BigEndian.PutUint16(ethertype, uint16(event.Protocol)) 362 | payload = append(payload, ethertype[1], ethertype[0]) 363 | captureInfo.Length += 14 364 | captureInfo.CaptureLength += 14 365 | 366 | } 367 | payload = append(payload, skbData...) 368 | if err = pcapw.WritePacket(captureInfo, payload); err != nil { 369 | log.Debug("failed to write packet", "err", err) 370 | } 371 | 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | func IsDigit(c string) (uint64, bool) { 9 | if strings.HasPrefix(c, "0x") { 10 | address, err := strconv.ParseUint(c[2:], 16, 64) 11 | if err == nil { 12 | return address, true 13 | } 14 | } 15 | 16 | address, err := strconv.ParseUint(c, 10, 64) 17 | if err == nil { 18 | return address, true 19 | } 20 | 21 | address, err = strconv.ParseUint(c, 16, 64) 22 | if err == nil { 23 | return address, true 24 | } 25 | 26 | return 0, false 27 | } 28 | 29 | func RegisterToCookie(register string) (cookie uint64) { 30 | switch register { 31 | case "R15": 32 | cookie = 1 33 | case "R14": 34 | cookie = 2 35 | case "R13": 36 | cookie = 3 37 | case "R12": 38 | cookie = 4 39 | case "RBP": 40 | cookie = 5 41 | case "RBX": 42 | cookie = 6 43 | case "R11": 44 | cookie = 7 45 | case "R10": 46 | cookie = 8 47 | case "R9": 48 | cookie = 9 49 | case "R8": 50 | cookie = 10 51 | case "RAX": 52 | cookie = 11 53 | case "RCX": 54 | cookie = 12 55 | case "RDX": 56 | cookie = 13 57 | case "RSI": 58 | cookie = 14 59 | case "RDI": 60 | cookie = 15 61 | } 62 | return 63 | } 64 | --------------------------------------------------------------------------------