├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── assets │ ├── README.md │ ├── bpftool_ball.svg │ ├── bpftool_horizontal_color.svg │ ├── bpftool_horizontal_monochrome.svg │ ├── bpftool_horizontal_monochrome_reversed.svg │ ├── bpftool_icon_color.svg │ ├── bpftool_icon_monochrome.svg │ ├── bpftool_icon_monochrome_reversed.svg │ ├── bpftool_stacked_color.svg │ ├── bpftool_stacked_monochrome.svg │ └── bpftool_stacked_monochrome_reversed.svg └── workflows │ ├── build.yaml │ ├── docker.yaml │ ├── lint-commits.yaml │ ├── lint-shell.yaml │ ├── release.yaml │ └── static-build.yaml ├── .gitmodules ├── .mailmap ├── BPF-CHECKPOINT-COMMIT ├── CHECKPOINT-COMMIT ├── Dockerfile ├── LICENSE ├── LICENSE.BSD-2-Clause ├── LICENSE.GPL-2.0 ├── README.md ├── bash-completion └── bpftool ├── docs ├── .gitignore ├── Makefile ├── bpftool-btf.rst ├── bpftool-cgroup.rst ├── bpftool-feature.rst ├── bpftool-gen.rst ├── bpftool-iter.rst ├── bpftool-link.rst ├── bpftool-map.rst ├── bpftool-net.rst ├── bpftool-perf.rst ├── bpftool-prog.rst ├── bpftool-struct_ops.rst ├── bpftool.rst ├── common_options.rst └── substitutions.rst ├── include ├── linux │ ├── bitops.h │ ├── build_bug.h │ ├── compiler-gcc.h │ ├── compiler.h │ ├── compiler_types.h │ ├── err.h │ ├── filter.h │ ├── kernel.h │ ├── list.h │ ├── sizes.h │ ├── stringify.h │ └── types.h ├── tools │ └── dis-asm-compat.h └── uapi │ ├── asm-generic │ └── bitsperlong.h │ └── linux │ ├── bpf.h │ ├── bpf_common.h │ ├── btf.h │ ├── const.h │ ├── if_link.h │ ├── netlink.h │ ├── perf_event.h │ ├── pkt_cls.h │ ├── pkt_sched.h │ └── tc_act │ └── tc_bpf.h ├── scripts ├── README.md ├── gh-label-release-assets.sh ├── mailmap-update.sh ├── sync-kernel-expected-diff.patch └── sync-kernel.sh └── src ├── .gitignore ├── Makefile ├── Makefile.feature ├── Makefile.include ├── btf.c ├── btf_dumper.c ├── cfg.c ├── cfg.h ├── cgroup.c ├── common.c ├── feature.c ├── gen.c ├── iter.c ├── jit_disasm.c ├── json_writer.c ├── json_writer.h ├── kernel └── bpf │ ├── disasm.c │ └── disasm.h ├── link.c ├── main.c ├── main.h ├── map.c ├── map_perf_ring.c ├── net.c ├── netlink_dumper.c ├── netlink_dumper.h ├── perf.c ├── pids.c ├── prog.c ├── skeleton ├── pid_iter.bpf.c ├── pid_iter.h └── profiler.bpf.c ├── struct_ops.c ├── tracelog.c ├── xlated_dumper.c └── xlated_dumper.h /.gitattributes: -------------------------------------------------------------------------------- 1 | src/Makefile.* linguist-language=Makefile 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report an issue when building or using bpftool 4 | --- 5 | 6 | ## Reporting an issue 7 | 8 | 21 | 22 | - [ ] I considered whether to report to the BPF mailing list first 23 | 24 | ## Environment 25 | 26 | - bpftool version: 27 | - Linux kernel version: 28 | - (optionally) clang/LLVM version: 29 | - ... 30 | 31 | ## Describe the bug 32 | 33 | 37 | -------------------------------------------------------------------------------- /.github/assets/README.md: -------------------------------------------------------------------------------- 1 | # A logo for bpftool [![License: CC BY 4.0][badge]][cc-by-4.0] 2 | 3 | [badge]: https://img.shields.io/badge/License-CC_BY_4.0-blue.svg 4 | [cc-by-4.0]: https://creativecommons.org/licenses/by/4.0/ 5 | 6 | ![bpftool logo](bpftool_stacked_color.svg) 7 | 8 | Meet **Hannah the Honeyguide**, bpftool's mascot. She is a [greater 9 | honeyguide](https://en.wikipedia.org/wiki/Greater_honeyguide), but a juvenile 10 | one, as can be seen from her yellow throat. We accentuated her shades, because 11 | Hannah really wanted to share colors with eBee and Tux (the mascots for eBPF 12 | and Linux, respectively). 13 | 14 | Living in sub-Saharan Africa, greater honeyguides are known for guiding humans 15 | to the nests of wild bees. They use a specific call to attract human attention, 16 | then they fly towards the hive. Once the honey hunters have found and harvested 17 | the nest, greater honeyguides feed on the remnants of the hive, eating bee eggs 18 | and larvae, and even beeswax. 19 | 20 | Like a honeyguide, bpftool guides humans towards bees, or to be more accurate, 21 | towards BPF objects loaded on a system: after all, one of the primary use cases 22 | for bpftool is to load and inspect BPF programs and maps. Don't worry, bpftool 23 | will not eat your programs. Although, it could well detach programs and have 24 | them removed from the kernel, if you asked it to. Of course, bpftool is a piece 25 | of software and cannot "expect" to receive something in return for its 26 | services. But think of it this way: for guiding humans to BPF, it feeds on 27 | software maintenance and new features. Isn't that some form of mutualism, after 28 | all? 29 | 30 | Greater honeyguides are also brood parasites: the females lay their eggs in the 31 | nests of birds of different species, and the chicks attempt to get rid of any 32 | competitors as soon as they hatch. Thankfully, Hannah chose not to fight at 33 | birth. As for bpftool? Shhhh, we may well have placed it in a particular 34 | penguin's nest, so it could thrive. But we're happy to report that bpftool 35 | never pushed any other project out of the Linux repository! 36 | 37 | **License:** The logos are licensed under the [Creative Commons Attribution 4.0 38 | International (CC-BY-4.0)][cc-by-4.0]. Reuse them as you want, but please 39 | credit the bpftool authors. The logos were designed by Quentin Monnet. The font 40 | used to typeset "bpftool" is 41 | [Raleway](https://www.theleagueofmoveabletype.com/raleway). 42 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/workflows/build.yaml' 7 | - 'docs/**' 8 | - 'include/**' 9 | - 'libbpf/**' 10 | - 'src/**' 11 | push: 12 | branches: 13 | - main 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | build: 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | os: [ubuntu-22.04] 25 | runs-on: ${{ matrix.os }} 26 | env: 27 | FEATURES: .llvm and .skeletons 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 32 | with: 33 | submodules: true 34 | 35 | - name: Install dependencies 36 | run: | 37 | sudo apt-get update 38 | sudo apt-get install -y \ 39 | libbfd-dev libcap-dev libelf-dev libiberty-dev python3-docutils 40 | # clang/LLVM are already installed, but we're missing some aliases. 41 | CLANG_VERSION="$(echo '__clang_major__' | clang -E - | tail -n 1)" 42 | sudo update-alternatives \ 43 | --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-"${CLANG_VERSION}" 50 \ 44 | --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-"${CLANG_VERSION}" \ 45 | --slave /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-"${CLANG_VERSION}" 46 | echo "CLANG_VERSION=${CLANG_VERSION}" >> "${GITHUB_ENV}" 47 | 48 | - name: Build bpftool (default LLVM disassembler) 49 | run: | 50 | make -j -C src V=1 51 | ./src/bpftool 2>&1 | grep -q Usage 52 | ./src/bpftool -p version | \ 53 | tee /dev/stderr | \ 54 | jq --exit-status ".features | ${FEATURES}" 55 | 56 | - name: Build bpftool, with clang 57 | run: | 58 | make -C src clean 59 | LLVM=1 make -j -C src V=1 60 | ./src/bpftool 2>&1 | grep -q Usage 61 | ./src/bpftool -p version | \ 62 | tee /dev/stderr | \ 63 | jq --exit-status ".features | ${FEATURES}" 64 | 65 | - name: Build bpftool, with fallback to libbfd disassembler 66 | run: | 67 | sudo apt-get remove -y llvm-"${CLANG_VERSION}"-dev 68 | make -C src clean 69 | make -j -C src V=1 70 | ./src/bpftool 2>&1 | grep -q Usage 71 | ./src/bpftool -p version | \ 72 | tee /dev/stderr | \ 73 | jq --exit-status ".features | .libbfd and (.llvm | not)" 74 | 75 | - name: Build bpftool, with libbfd, static build 76 | run: | 77 | make -C src clean 78 | EXTRA_CFLAGS=--static make -j -C src V=1 79 | ./src/bpftool 2>&1 | grep -q Usage 80 | ./src/bpftool -p version | \ 81 | tee /dev/stderr | \ 82 | jq --exit-status ".features | .libbfd and (.llvm | not)" 83 | ldd ./src/bpftool 2>&1 | \ 84 | tee /dev/stderr | \ 85 | grep -q 'not a dynamic executable' 86 | 87 | - name: Build bpftool's documentation 88 | run: | 89 | make -j -C docs 90 | grep -q '.TH "\?BPFTOOL"\? 8' ./docs/bpftool.8 91 | -------------------------------------------------------------------------------- /.github/workflows/docker.yaml: -------------------------------------------------------------------------------- 1 | name: docker 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/workflows/docker.yaml' 7 | - 'Dockerfile' 8 | - 'include/**' 9 | - 'libbpf/**' 10 | - 'src/**' 11 | push: 12 | branches: 13 | - main 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | dockerimage: 21 | name: Docker image 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 26 | with: 27 | submodules: recursive 28 | 29 | - name: Build bpftool container image 30 | uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # v4.0.0 31 | with: 32 | push: false 33 | tags: bpftool:latest 34 | 35 | - name: Test bpftool container image 36 | run: | 37 | docker run --rm --privileged --pid=host bpftool version 38 | docker run --rm --privileged --pid=host bpftool prog 39 | docker run --rm --privileged --pid=host bpftool map 40 | 41 | - name: Lint Docker image 42 | uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 43 | with: 44 | dockerfile: Dockerfile 45 | -------------------------------------------------------------------------------- /.github/workflows/lint-commits.yaml: -------------------------------------------------------------------------------- 1 | name: lint-commits 2 | 3 | on: 4 | pull_request: 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.event.pull_request.number }} 8 | cancel-in-progress: true 9 | 10 | jobs: 11 | checkCommits: 12 | name: check commits 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Get list of commits 21 | run: | 22 | read PR_BASE PR_TIP < <(curl -L \ 23 | -H "Accept: application/vnd.github.v3+json" \ 24 | -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ 25 | -H "X-GitHub-Api-Version: 2022-11-28" \ 26 | ${{ github.event.pull_request.url }} | \ 27 | tee /dev/stderr | \ 28 | jq -r '"\(.base.sha) \(.head.sha)"' | \ 29 | tee /dev/stderr) 30 | echo "PR_TIP=${PR_TIP}" >> "${GITHUB_ENV}" 31 | echo "PR_BASE=${PR_BASE}" >> "${GITHUB_ENV}" 32 | 33 | - name: Check commit prefixes 34 | run: | 35 | if [[ -z "${PR_TIP}" || -z "${PR_BASE}" ]]; then 36 | echo "::error title=invalid base and head:: Failed to retrieve base and head for Pull Request" 37 | # Fail workflow 38 | false 39 | fi 40 | START_MARKER='sync: Update libbpf submodule' 41 | END_MARKER='sync: Pull latest bpftool changes from kernel' 42 | declare -a PREFIXES=( 43 | "ci" 44 | "mirror" 45 | ) 46 | 47 | misformed=0 48 | syncing=0 49 | while read commit ; do 50 | valid=1 51 | sha="${commit%% *}" 52 | object="${commit#* }" 53 | case "${object}" in 54 | "${START_MARKER}") 55 | syncing=1 56 | ;; 57 | "${END_MARKER}") 58 | syncing=0 59 | ;; 60 | *) 61 | if [[ "${syncing}" == 0 ]]; then 62 | valid=0 63 | for prefix in "${PREFIXES[@]}"; do 64 | if [[ "${object}" =~ ^"${prefix}: " ]]; then 65 | valid=1 66 | break 67 | fi 68 | done 69 | fi 70 | ;; 71 | esac 72 | if [[ "${valid}" = 1 ]]; then 73 | echo "::notice title=valid prefix::${sha} (\"${object}\") has a valid prefix" 74 | else 75 | echo "::error title=invalid prefix::${sha} (\"${object}\") does not have a valid prefix" 76 | misformed=$((misformed+1)) 77 | fi 78 | done < <(git log --format='%h %s' --reverse ${{ env.PR_BASE }}..${{ env.PR_TIP }}) 79 | 80 | echo "::notice ::Found ${misformed} invalid commit object(s)" 81 | if [[ "${misformed}" != 0 ]]; then 82 | echo "Please ensure all commits not part of kernel sync are prefixed with one of:" 83 | echo " ${PREFIXES[@]/%/:}" 84 | # Fail workflow 85 | false 86 | fi 87 | -------------------------------------------------------------------------------- /.github/workflows/lint-shell.yaml: -------------------------------------------------------------------------------- 1 | name: lint-shell 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/workflows/lint-shell.yaml' 7 | - 'scripts/**' 8 | push: 9 | branches: 10 | - main 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | shellcheck: 18 | name: ShellCheck 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 23 | 24 | - name: Run ShellCheck 25 | uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 26 | with: 27 | scandir: './scripts' 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: build and release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v[0-9]+.[0-9]+.[0-9]*' 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.after }} 10 | cancel-in-progress: true 11 | 12 | env: 13 | # https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.0 14 | LLVM_URL_PREFIX: https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.0 15 | LLVM_arm64: clang+llvm-15.0.0-aarch64-linux-gnu 16 | LLVM_amd64: clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4 17 | 18 | jobs: 19 | build: 20 | name: Build static bpftool binary 21 | runs-on: ubuntu-22.04 22 | env: 23 | TARGETARCH: ${{ matrix.arch }} 24 | FILE_STRING_ARCH_amd64: x86-64 25 | FILE_STRING_ARCH_arm64: aarch64 26 | strategy: 27 | matrix: 28 | arch: [arm64, amd64] 29 | 30 | steps: 31 | # amd64 needs the dependencies to build bpftool 32 | - name: Install dependencies (amd64) 33 | if: matrix.arch == 'amd64' 34 | run: | 35 | sudo apt-get update 36 | sudo apt-get install -y libelf-dev libcap-dev 37 | 38 | - name: Download and extract compiled LLVM release 39 | env: 40 | LLVM: ${{ env[format('LLVM_{0}', matrix.arch)] }} 41 | run: | 42 | curl -L -O "${{ env.LLVM_URL_PREFIX}}/${{ env.LLVM }}.tar.xz" 43 | tar -xvf "${{ env.LLVM }}.tar.xz" 44 | 45 | - name: Checkout bpftool code 46 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 47 | with: 48 | submodules: recursive 49 | # Create a new directory to avoid wiping out LLVM on bpftool checkout 50 | path: 'bpftool' 51 | 52 | - name: Build static bpftool natively for amd64 53 | if: matrix.arch == 'amd64' 54 | working-directory: 'bpftool' 55 | env: 56 | LLVM_PATH: ${{ env[format('LLVM_{0}', matrix.arch)] }} 57 | run: | 58 | EXTRA_CFLAGS=--static \ 59 | LLVM_CONFIG="${GITHUB_WORKSPACE}/${{ env.LLVM_PATH }}/bin/llvm-config" \ 60 | LLVM_STRIP="${GITHUB_WORKSPACE}/${{ env.LLVM_PATH }}/bin/llvm-strip" \ 61 | HOSTAR="${GITHUB_WORKSPACE}/${{ env.LLVM_PATH }}/bin/llvm-ar" \ 62 | make -j -C src V=1 63 | strip src/bpftool 64 | 65 | - name: Set up QEMU 66 | uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 67 | if: matrix.arch == 'arm64' 68 | with: 69 | platforms: arm64 70 | 71 | # The emulated build leverages Docker and Ubuntu 22.04 container image 72 | # distribution to have all the needed arm64 packages. 73 | - name: Build static bpftool for arm64 with emulation 74 | if: matrix.arch == 'arm64' 75 | env: 76 | LLVM_PATH: ${{ env[format('LLVM_{0}', matrix.arch)] }} 77 | run: | 78 | docker run --platform linux/arm64 --rm -v $(pwd):/build ubuntu:22.04 \ 79 | bash -c "apt-get update && \ 80 | apt-get install -y make pkg-config gcc \ 81 | libelf-dev libcap-dev libstdc++-11-dev zlib1g-dev && \ 82 | cd /build/bpftool && \ 83 | EXTRA_CFLAGS=--static \ 84 | LLVM_CONFIG='/build/${{ env.LLVM_PATH }}/bin/llvm-config' \ 85 | LLVM_STRIP='/build/${{ env.LLVM_PATH }}/bin/llvm-strip' \ 86 | CLANG='/build/${{ env.LLVM_PATH }}/bin/clang' \ 87 | make -j -C src V=1 && \ 88 | strip src/bpftool" 89 | 90 | - name: Test bpftool binary 91 | working-directory: 'bpftool/src' 92 | env: 93 | ARCH: ${{ env[format('FILE_STRING_ARCH_{0}', matrix.arch)] }} 94 | run: | 95 | file ./bpftool | \ 96 | tee /dev/stderr | \ 97 | grep -q "${{ env.ARCH }}" 98 | ./bpftool 2>&1 | grep -q Usage 99 | ./bpftool -p version | \ 100 | tee /dev/stderr | \ 101 | jq --exit-status ".features | .llvm and .skeletons" 102 | ldd ./bpftool 2>&1 | \ 103 | tee /dev/stderr | \ 104 | grep -q 'not a dynamic executable' 105 | 106 | - name: Upload Artifact 107 | uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 108 | with: 109 | name: ${{ format('bpftool_{0}', matrix.arch) }} 110 | path: bpftool/src/bpftool 111 | 112 | draft-release: 113 | name: Create a draft release 114 | runs-on: ubuntu-22.04 115 | needs: build 116 | permissions: 117 | contents: write 118 | steps: 119 | - name: Download artifacts from build 120 | uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 121 | 122 | - name: Rename binaries and compress 123 | run: | 124 | archive_amd64="bpftool-${{ github.ref_name }}-amd64.tar.gz" 125 | archive_arm64="bpftool-${{ github.ref_name }}-arm64.tar.gz" 126 | tar -C bpftool_amd64 -I 'gzip -9' -cvf "${archive_amd64}" bpftool 127 | tar -C bpftool_arm64 -I 'gzip -9' -cvf "${archive_arm64}" bpftool 128 | sha256sum "${archive_amd64}" > "${archive_amd64}.sha256sum" 129 | sha256sum "${archive_arm64}" > "${archive_arm64}.sha256sum" 130 | 131 | - name: Checkout bpftool and libbpf code 132 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 133 | with: 134 | submodules: recursive 135 | path: 'bpftool' 136 | 137 | - name: Package source code including submodules 138 | uses: qmonnet/git-archive-all-action@791fb850881cf58b1d1fcc9b06c01940080bba0a # v1.0.1 139 | with: 140 | output-files: bpftool-libbpf-${{ github.ref_name }}-sources.tar.gz 141 | base-repo: bpftool 142 | 143 | - name: Create draft release and add artifacts 144 | uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 145 | with: 146 | draft: true 147 | files: bpftool* 148 | -------------------------------------------------------------------------------- /.github/workflows/static-build.yaml: -------------------------------------------------------------------------------- 1 | name: static LLVM build 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/workflows/static-build.yaml' 7 | - 'include/**' 8 | - 'libbpf/**' 9 | - 'src/**' 10 | push: 11 | branches: 12 | - main 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.after }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-22.04 21 | env: 22 | LLVM_URL_PREFIX: https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.0 23 | LLVM_PATH: clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4 24 | 25 | steps: 26 | - name: Install dependencies 27 | run: | 28 | sudo apt-get update 29 | sudo apt-get install -y libelf-dev 30 | 31 | - name: Download and extract compiled LLVM release 32 | run: | 33 | curl -L -O "${{ env.LLVM_URL_PREFIX }}/${{ env.LLVM_PATH }}.tar.xz" 34 | tar -xvf "${{ env.LLVM_PATH }}.tar.xz" 35 | 36 | - name: Checkout bpftool 37 | uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 38 | with: 39 | submodules: recursive 40 | # Create a new directory to avoid wiping out LLVM on bpftool checkout 41 | path: 'bpftool' 42 | 43 | - name: Build bpftool (static build, default LLVM disassembler) 44 | working-directory: 'bpftool' 45 | run: | 46 | EXTRA_CFLAGS=--static \ 47 | LLVM_CONFIG="${GITHUB_WORKSPACE}/${LLVM_PATH}/bin/llvm-config" \ 48 | LLVM_STRIP="${GITHUB_WORKSPACE}/${LLVM_PATH}/bin/llvm-strip" \ 49 | make -j -C src V=1 50 | 51 | - name: Test bpftool binary 52 | working-directory: 'bpftool' 53 | run: | 54 | ./src/bpftool 2>&1 | grep -q Usage 55 | ./src/bpftool -p version | \ 56 | tee /dev/stderr | \ 57 | jq --exit-status ".features | .llvm" 58 | ldd ./src/bpftool 2>&1 | \ 59 | tee /dev/stderr | \ 60 | grep -q 'not a dynamic executable' 61 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libbpf"] 2 | path = libbpf 3 | url = https://github.com/libbpf/libbpf.git 4 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Changbin Du 2 | Fangrui Song 3 | Geliang Tang 4 | Herbert Xu 5 | Jesper Dangaard Brouer 6 | Kees Cook 7 | Maxim Mikityanskiy 8 | Quentin Monnet 9 | Stanislav Fomichev 10 | Thorsten Blum 11 | Vadim Fedorenko 12 | Yanteng Si 13 | -------------------------------------------------------------------------------- /BPF-CHECKPOINT-COMMIT: -------------------------------------------------------------------------------- 1 | b4432656b36e5cc1d50a1f2dc15357543add530e 2 | -------------------------------------------------------------------------------- /CHECKPOINT-COMMIT: -------------------------------------------------------------------------------- 1 | 9325d53fe9adff354b6a93fda5f38c165947da0f 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # With this Dockerfile, you can create a container image: 2 | # $ docker build -f Dockerfile -t bpftool . 3 | # And then use it: 4 | # $ docker run --rm -ti --privileged --pid=host bpftool prog 5 | 6 | # hadolint global ignore=DL3008 7 | 8 | FROM ubuntu:22.04 as builder 9 | 10 | RUN \ 11 | export DEBIAN_FRONTEND=noninteractive && \ 12 | apt-get update && \ 13 | apt-get -y install --no-install-recommends \ 14 | build-essential \ 15 | libelf-dev \ 16 | libz-dev \ 17 | libcap-dev \ 18 | clang llvm llvm-dev lld \ 19 | binutils-dev \ 20 | pkg-config && \ 21 | rm -rf /var/lib/apt/lists/* 22 | 23 | COPY . /src 24 | RUN \ 25 | make -C /src/src clean && \ 26 | make -C /src/src -j "$(nproc)" 27 | 28 | FROM ubuntu:22.04 29 | RUN \ 30 | export DEBIAN_FRONTEND=noninteractive && \ 31 | apt-get update && \ 32 | apt-get -y install --no-install-recommends \ 33 | libelf1 \ 34 | llvm && \ 35 | rm -rf /var/lib/apt/lists/* 36 | 37 | COPY --from=builder /src/src/bpftool /bin/bpftool 38 | 39 | ENTRYPOINT ["/bin/bpftool"] 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GPL-2.0-only OR BSD-2-Clause 2 | -------------------------------------------------------------------------------- /LICENSE.BSD-2-Clause: -------------------------------------------------------------------------------- 1 | Valid-License-Identifier: BSD-2-Clause 2 | SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html 3 | Usage-Guide: 4 | To use the BSD 2-clause "Simplified" License put the following SPDX 5 | tag/value pair into a comment according to the placement guidelines in 6 | the licensing rules documentation: 7 | SPDX-License-Identifier: BSD-2-Clause 8 | License-Text: 9 | 10 | Copyright (c) . All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, 16 | this list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | bpftool logo: Hannah the Honeyguide 6 |
7 |
8 | 9 | [![License BSD 2-Clause][bsd-badge]](LICENSE.BSD-2-Clause) 10 | [![License GPL 2.0][gpl-badge]](LICENSE.GPL-2.0) 11 | [![Build status][build-badge]][build] 12 | 13 | [bsd-badge]: https://img.shields.io/badge/License-BSD_2--Clause-blue.svg 14 | [gpl-badge]: https://img.shields.io/badge/License-GPL_2.0-blue.svg 15 | [build-badge]: https://github.com/libbpf/bpftool/actions/workflows/build.yaml/badge.svg 16 | [build]: https://github.com/libbpf/bpftool/actions/workflows/build.yaml 17 | 18 | This is the official home for bpftool. _Please use this Github repository for 19 | building and packaging bpftool and when using it in your projects through Git 20 | submodule._ 21 | 22 | The _authoritative source code_ of bpftool is developed as part of the 23 | [bpf-next Linux source tree][bpf-next] under [the `tools/bpf/bpftool` 24 | subdirectory][tools-bpf-bpftool] and is periodically synced to 25 | on Github. As such, all changes for bpftool 26 | **should be sent to the [BPF mailing list][bpf-ml]**, **please don't open PRs 27 | here** unless you are changing some Github-specific components. 28 | 29 | [bpf-next]: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git 30 | [tools-bpf-bpftool]: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/bpf/bpftool 31 | [bpf-ml]: http://vger.kernel.org/vger-lists.html#bpf 32 | 33 | Questions on bpftool and BPF general usage 34 | ------------------------------------------ 35 | 36 | Check out [the manual pages](docs) for documentation about bpftool. A number of 37 | example invocations are also displayed in [this blog 38 | post](https://qmonnet.github.io/whirl-offload/2021/09/23/bpftool-features-thread/). 39 | 40 | All general BPF questions, including kernel functionality, bpftool features and 41 | usage, should be sent to bpf@vger.kernel.org mailing list. You can subscribe to 42 | it [here][bpf-ml] and search its archives [here][lore]. 43 | 44 | The mailing list is monitored by many more people than this repo and they will 45 | happily try to help you with whatever issue you encounter. This repository's 46 | PRs and issues should be opened only for dealing with issues related to 47 | components specific to the bpftool mirror repository (such as the 48 | synchronization script or the CI workflows). The project maintainers also use 49 | GitHub issues as a generic tracker for bpftool, but issues should first be 50 | reported on the mailing list nonetheless. 51 | 52 | [lore]: https://lore.kernel.org/bpf/ 53 | 54 | Dependencies 55 | ------------ 56 | 57 | Required: 58 | 59 | - libelf 60 | - zlib 61 | 62 | Optional: 63 | 64 | - libbfd (for dumping JIT-compiled program instructions) 65 | - libcap (for better feature probing) 66 | - kernel BTF information (for profiling programs or showing PIDs of processes 67 | referencing BPF objects) 68 | - clang/LLVM (idem) 69 | 70 | Build 71 | ----- 72 | 73 | ### Initialize libbpf submodule 74 | 75 | This repository uses libbpf as a submodule. You can initialize it when cloning 76 | bpftool: 77 | 78 | ```console 79 | $ git clone --recurse-submodules https://github.com/libbpf/bpftool.git 80 | ``` 81 | 82 | Alternatively, if you have already cloned the repository, you can initialize 83 | the submodule by running the following command from within the repository: 84 | 85 | ```console 86 | $ git submodule update --init 87 | ``` 88 | 89 | ### Build bpftool 90 | 91 | To build bpftool: 92 | 93 | ```console 94 | $ cd src 95 | $ make 96 | ``` 97 | 98 | To build and install bpftool on the system: 99 | 100 | ```console 101 | $ cd src 102 | # make install 103 | ``` 104 | 105 | Building bpftool in a separate directory is supported via the `OUTPUT` variable: 106 | 107 | ```console 108 | $ mkdir /tmp/bpftool 109 | $ cd src 110 | $ OUTPUT=/tmp/bpftool make 111 | ``` 112 | 113 | Most of the output is suppressed by default, but detailed building logs can be 114 | displayed by passing `V=1`: 115 | 116 | ```console 117 | $ cd src 118 | $ make V=1 119 | ``` 120 | 121 | Additional compilation flags can be passed to the command line if required. For 122 | example, we can create a static build with the following commands: 123 | 124 | ```console 125 | $ cd src 126 | $ EXTRA_CFLAGS=--static make 127 | ``` 128 | 129 | Note that to use the LLVM disassembler with static builds, we need a static 130 | version of the LLVM library installed on the system: 131 | 132 | 1. Download a precompiled LLVM release or build it locally. 133 | 134 | - Download the appropriate 135 | [release of LLVM](https://releases.llvm.org/download.html) for your 136 | platform, for example on x86_64 with LLVM 15.0.0: 137 | 138 | ```console 139 | $ curl -LO https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.0/clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4.tar.xz 140 | $ tar xvf clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4.tar.xz 141 | $ mv clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4 llvm_build 142 | ``` 143 | 144 | - Alternatively, clone and build the LLVM libraries locally. 145 | 146 | ```console 147 | $ git clone https://github.com/llvm/llvm-project.git 148 | $ mkdir llvm_build 149 | $ cmake -S llvm-project/llvm -B llvm_build -DCMAKE_BUILD_TYPE=Release 150 | $ make -j -C llvm_build llvm-config llvm-libraries 151 | ``` 152 | 153 | 2. Build bpftool with `EXTRA_CFLAGS` set to `--static`, and by passing the 154 | path to the relevant `llvm-config`. 155 | 156 | ```console 157 | $ cd bpftool 158 | $ LLVM_CONFIG=../../llvm_build/bin/llvm-config EXTRA_CFLAGS=--static make -j -C src 159 | ``` 160 | 161 | ### Build bpftool's man pages 162 | 163 | The man pages for bpftool can be built with: 164 | 165 | ```console 166 | $ cd docs 167 | $ make 168 | ``` 169 | 170 | They can be installed on the system with: 171 | 172 | ```console 173 | $ cd docs 174 | # make install 175 | ``` 176 | 177 | bpf-next to GitHub sync 178 | ----------------------- 179 | 180 | This repository mirrors [bpf-next Linux source tree's 181 | `tools/bpf/bpftool`][tools-bpf-bpftool] directory, plus its few dependencies 182 | from under `kernel/bpf/`, and its supporting header files. Some of these header 183 | files, `include/linux/*.h` on the current repository, are reduced versions of 184 | their counterpart files at [bpf-next][bpf-next]'s `tools/include/linux/*.h` to 185 | make compilation successful. 186 | 187 | Synchronization between the two repositories happens every few weeks or so. 188 | Given that bpftool remains aligned on libbpf's version, its repository tends to 189 | follow libbpf's. When the libbpf repo syncs up with bpf-next, bpftool's repo 190 | usually follows within the next few days. 191 | 192 | The synchronization process is semi-automated: the script in 193 | `scripts/sync-kernel.sh` cherry-picks, adjusts and commits all changes from 194 | `bpf-next` to a local version of the bpftool repository. However, maintainers 195 | run this script manually and then create a pull request to merge the resulting 196 | commits. 197 | 198 | Take a look at [the script](scripts/sync-kernel.sh) for the technical details of the process. See also the documentation in [the accompanying README.md](scripts#sync-kernelsh) 199 | 200 | License 201 | ------- 202 | 203 | This work is dual-licensed under the GNU GPL v2.0 (only) license and the BSD 204 | 2-clause license. You can select either of them if you reuse this work. 205 | 206 | `SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)` 207 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | bpftool*.8 3 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | include ../src/Makefile.include 3 | 4 | INSTALL ?= install 5 | RM ?= rm -f 6 | RMDIR ?= rmdir --ignore-fail-on-non-empty 7 | 8 | prefix ?= /usr/local 9 | mandir ?= $(prefix)/man 10 | man8dir = $(mandir)/man8 11 | 12 | MAN8_RST = $(wildcard bpftool*.rst) 13 | 14 | _DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) 15 | DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) 16 | 17 | man: man8 18 | man8: $(DOC_MAN8) 19 | 20 | RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) 21 | RST2MAN_OPTS += --verbose --strip-comments 22 | 23 | list_pages = $(sort $(basename $(filter-out $(1),$(MAN8_RST)))) 24 | see_also = $(subst " ",, \ 25 | "\n" \ 26 | "SEE ALSO\n" \ 27 | "========\n" \ 28 | "**bpf**\ (2),\n" \ 29 | "**bpf-helpers**\\ (7)" \ 30 | $(foreach page,$(call list_pages,$(1)),",\n**$(page)**\\ (8)") \ 31 | "\n") 32 | 33 | $(OUTPUT)%.8: %.rst 34 | ifndef RST2MAN_DEP 35 | $(error "rst2man not found, but required to generate man pages") 36 | endif 37 | $(QUIET_GEN)( cat $< ; printf "%b" $(call see_also,$<) ) | rst2man $(RST2MAN_OPTS) > $@ 38 | 39 | clean: 40 | $(call QUIET_CLEAN, Documentation) 41 | $(Q)$(RM) $(DOC_MAN8) 42 | 43 | install: man 44 | $(call QUIET_INSTALL, Documentation-man) 45 | $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir) 46 | $(Q)$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir) 47 | 48 | uninstall: 49 | $(call QUIET_UNINST, Documentation-man) 50 | $(Q)$(RM) $(addprefix $(DESTDIR)$(man8dir)/,$(_DOC_MAN8)) 51 | $(Q)$(RMDIR) $(DESTDIR)$(man8dir) 52 | 53 | .PHONY: man man8 clean install uninstall 54 | .DEFAULT_GOAL := man 55 | -------------------------------------------------------------------------------- /docs/bpftool-btf.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | bpftool-btf 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection of BTF data 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **btf** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| | { **-B** | **--base-btf** } } 20 | 21 | *COMMANDS* := { **dump** | **help** } 22 | 23 | BTF COMMANDS 24 | ============= 25 | 26 | | **bpftool** **btf** { **show** | **list** } [**id** *BTF_ID*] 27 | | **bpftool** **btf dump** *BTF_SRC* [**format** *FORMAT*] [**root_id** *ROOT_ID*] 28 | | **bpftool** **btf help** 29 | | 30 | | *BTF_SRC* := { **id** *BTF_ID* | **prog** *PROG* | **map** *MAP* [{**key** | **value** | **kv** | **all**}] | **file** *FILE* } 31 | | *FORMAT* := { **raw** | **c** [**unsorted**] } 32 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } 33 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* } 34 | 35 | DESCRIPTION 36 | =========== 37 | bpftool btf { show | list } [id *BTF_ID*] 38 | Show information about loaded BTF objects. If a BTF ID is specified, show 39 | information only about given BTF object, otherwise list all BTF objects 40 | currently loaded on the system. 41 | 42 | Since Linux 5.8 bpftool is able to discover information about processes 43 | that hold open file descriptors (FDs) against BTF objects. On such kernels 44 | bpftool will automatically emit this information as well. 45 | 46 | bpftool btf dump *BTF_SRC* [format *FORMAT*] [root_id *ROOT_ID*] 47 | Dump BTF entries from a given *BTF_SRC*. 48 | 49 | When **id** is specified, BTF object with that ID will be loaded and all 50 | its BTF types emitted. 51 | 52 | When **map** is provided, it's expected that map has associated BTF object 53 | with BTF types describing key and value. It's possible to select whether to 54 | dump only BTF type(s) associated with key (**key**), value (**value**), 55 | both key and value (**kv**), or all BTF types present in associated BTF 56 | object (**all**). If not specified, **kv** is assumed. 57 | 58 | When **prog** is provided, it's expected that program has associated BTF 59 | object with BTF types. 60 | 61 | When specifying *FILE*, an ELF file is expected, containing .BTF section 62 | with well-defined BTF binary format data, typically produced by clang or 63 | pahole. 64 | 65 | **format** option can be used to override default (raw) output format. Raw 66 | (**raw**) or C-syntax (**c**) output formats are supported. With C-style 67 | formatting, the output is sorted by default. Use the **unsorted** option 68 | to avoid sorting the output. 69 | 70 | **root_id** option can be used to filter a dump to a single type and all 71 | its dependent types. It cannot be used with any other types of filtering 72 | (such as the "key", "value", or "kv" arguments when dumping BTF for a map). 73 | It can be passed multiple times to dump multiple types. 74 | 75 | bpftool btf help 76 | Print short help message. 77 | 78 | OPTIONS 79 | ======= 80 | .. include:: common_options.rst 81 | 82 | -B, --base-btf *FILE* 83 | Pass a base BTF object. Base BTF objects are typically used with BTF 84 | objects for kernel modules. To avoid duplicating all kernel symbols 85 | required by modules, BTF objects for modules are "split", they are 86 | built incrementally on top of the kernel (vmlinux) BTF object. So the 87 | base BTF reference should usually point to the kernel BTF. 88 | 89 | When the main BTF object to process (for example, the module BTF to 90 | dump) is passed as a *FILE*, bpftool attempts to autodetect the path 91 | for the base object, and passing this option is optional. When the main 92 | BTF object is passed through other handles, this option becomes 93 | necessary. 94 | 95 | EXAMPLES 96 | ======== 97 | **# bpftool btf dump id 1226** 98 | 99 | :: 100 | 101 | [1] PTR '(anon)' type_id=2 102 | [2] STRUCT 'dummy_tracepoint_args' size=16 vlen=2 103 | 'pad' type_id=3 bits_offset=0 104 | 'sock' type_id=4 bits_offset=64 105 | [3] INT 'long long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none) 106 | [4] PTR '(anon)' type_id=5 107 | [5] FWD 'sock' fwd_kind=union 108 | 109 | This gives an example of default output for all supported BTF kinds. 110 | 111 | **$ cat prog.c** 112 | 113 | :: 114 | 115 | struct fwd_struct; 116 | 117 | enum my_enum { 118 | VAL1 = 3, 119 | VAL2 = 7, 120 | }; 121 | 122 | typedef struct my_struct my_struct_t; 123 | 124 | struct my_struct { 125 | const unsigned int const_int_field; 126 | int bitfield_field: 4; 127 | char arr_field[16]; 128 | const struct fwd_struct *restrict fwd_field; 129 | enum my_enum enum_field; 130 | volatile my_struct_t *typedef_ptr_field; 131 | }; 132 | 133 | union my_union { 134 | int a; 135 | struct my_struct b; 136 | }; 137 | 138 | struct my_struct struct_global_var __attribute__((section("data_sec"))) = { 139 | .bitfield_field = 3, 140 | .enum_field = VAL1, 141 | }; 142 | int global_var __attribute__((section("data_sec"))) = 7; 143 | 144 | __attribute__((noinline)) 145 | int my_func(union my_union *arg1, int arg2) 146 | { 147 | static int static_var __attribute__((section("data_sec"))) = 123; 148 | static_var++; 149 | return static_var; 150 | } 151 | 152 | **$ bpftool btf dump file prog.o** 153 | 154 | :: 155 | 156 | [1] PTR '(anon)' type_id=2 157 | [2] UNION 'my_union' size=48 vlen=2 158 | 'a' type_id=3 bits_offset=0 159 | 'b' type_id=4 bits_offset=0 160 | [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED 161 | [4] STRUCT 'my_struct' size=48 vlen=6 162 | 'const_int_field' type_id=5 bits_offset=0 163 | 'bitfield_field' type_id=3 bits_offset=32 bitfield_size=4 164 | 'arr_field' type_id=8 bits_offset=40 165 | 'fwd_field' type_id=10 bits_offset=192 166 | 'enum_field' type_id=14 bits_offset=256 167 | 'typedef_ptr_field' type_id=15 bits_offset=320 168 | [5] CONST '(anon)' type_id=6 169 | [6] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none) 170 | [7] INT 'char' size=1 bits_offset=0 nr_bits=8 encoding=SIGNED 171 | [8] ARRAY '(anon)' type_id=7 index_type_id=9 nr_elems=16 172 | [9] INT '__ARRAY_SIZE_TYPE__' size=4 bits_offset=0 nr_bits=32 encoding=(none) 173 | [10] RESTRICT '(anon)' type_id=11 174 | [11] PTR '(anon)' type_id=12 175 | [12] CONST '(anon)' type_id=13 176 | [13] FWD 'fwd_struct' fwd_kind=union 177 | [14] ENUM 'my_enum' size=4 vlen=2 178 | 'VAL1' val=3 179 | 'VAL2' val=7 180 | [15] PTR '(anon)' type_id=16 181 | [16] VOLATILE '(anon)' type_id=17 182 | [17] TYPEDEF 'my_struct_t' type_id=4 183 | [18] FUNC_PROTO '(anon)' ret_type_id=3 vlen=2 184 | 'arg1' type_id=1 185 | 'arg2' type_id=3 186 | [19] FUNC 'my_func' type_id=18 187 | [20] VAR 'struct_global_var' type_id=4, linkage=global-alloc 188 | [21] VAR 'global_var' type_id=3, linkage=global-alloc 189 | [22] VAR 'my_func.static_var' type_id=3, linkage=static 190 | [23] DATASEC 'data_sec' size=0 vlen=3 191 | type_id=20 offset=0 size=48 192 | type_id=21 offset=0 size=4 193 | type_id=22 offset=52 size=4 194 | 195 | The following commands print BTF types associated with specified map's key, 196 | value, both key and value, and all BTF types, respectively. By default, both 197 | key and value types will be printed. 198 | 199 | **# bpftool btf dump map id 123 key** 200 | 201 | :: 202 | 203 | [39] TYPEDEF 'u32' type_id=37 204 | 205 | **# bpftool btf dump map id 123 value** 206 | 207 | :: 208 | 209 | [86] PTR '(anon)' type_id=87 210 | 211 | **# bpftool btf dump map id 123 kv** 212 | 213 | :: 214 | 215 | [39] TYPEDEF 'u32' type_id=37 216 | [86] PTR '(anon)' type_id=87 217 | 218 | **# bpftool btf dump map id 123 all** 219 | 220 | :: 221 | 222 | [1] PTR '(anon)' type_id=0 223 | . 224 | . 225 | . 226 | [2866] ARRAY '(anon)' type_id=52 index_type_id=51 nr_elems=4 227 | 228 | All the standard ways to specify map or program are supported: 229 | 230 | **# bpftool btf dump map id 123** 231 | 232 | **# bpftool btf dump map pinned /sys/fs/bpf/map_name** 233 | 234 | **# bpftool btf dump prog id 456** 235 | 236 | **# bpftool btf dump prog tag b88e0a09b1d9759d** 237 | 238 | **# bpftool btf dump prog pinned /sys/fs/bpf/prog_name** 239 | 240 | | 241 | | **# bpftool btf dump file /sys/kernel/btf/i2c_smbus** 242 | | (or) 243 | | **# I2C_SMBUS_ID=$(bpftool btf show -p | jq '.[] | select(.name=="i2c_smbus").id')** 244 | | **# bpftool btf dump id ${I2C_SMBUS_ID} -B /sys/kernel/btf/vmlinux** 245 | 246 | :: 247 | 248 | [104848] STRUCT 'i2c_smbus_alert' size=40 vlen=2 249 | 'alert' type_id=393 bits_offset=0 250 | 'ara' type_id=56050 bits_offset=256 251 | [104849] STRUCT 'alert_data' size=12 vlen=3 252 | 'addr' type_id=16 bits_offset=0 253 | 'type' type_id=56053 bits_offset=32 254 | 'data' type_id=7 bits_offset=64 255 | [104850] PTR '(anon)' type_id=104848 256 | [104851] PTR '(anon)' type_id=104849 257 | [104852] FUNC 'i2c_register_spd' type_id=84745 linkage=static 258 | [104853] FUNC 'smbalert_driver_init' type_id=1213 linkage=static 259 | [104854] FUNC_PROTO '(anon)' ret_type_id=18 vlen=1 260 | 'ara' type_id=56050 261 | [104855] FUNC 'i2c_handle_smbus_alert' type_id=104854 linkage=static 262 | [104856] FUNC 'smbalert_remove' type_id=104854 linkage=static 263 | [104857] FUNC_PROTO '(anon)' ret_type_id=18 vlen=2 264 | 'ara' type_id=56050 265 | 'id' type_id=56056 266 | [104858] FUNC 'smbalert_probe' type_id=104857 linkage=static 267 | [104859] FUNC 'smbalert_work' type_id=9695 linkage=static 268 | [104860] FUNC 'smbus_alert' type_id=71367 linkage=static 269 | [104861] FUNC 'smbus_do_alert' type_id=84827 linkage=static 270 | -------------------------------------------------------------------------------- /docs/bpftool-cgroup.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | bpftool-cgroup 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection and simple manipulation of eBPF progs 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **cgroup** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| | { **-f** | **--bpffs** } } 20 | 21 | *COMMANDS* := 22 | { **show** | **list** | **tree** | **attach** | **detach** | **help** } 23 | 24 | CGROUP COMMANDS 25 | =============== 26 | 27 | | **bpftool** **cgroup** { **show** | **list** } *CGROUP* [**effective**] 28 | | **bpftool** **cgroup tree** [*CGROUP_ROOT*] [**effective**] 29 | | **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] 30 | | **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG* 31 | | **bpftool** **cgroup help** 32 | | 33 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* } 34 | | *ATTACH_TYPE* := { **cgroup_inet_ingress** | **cgroup_inet_egress** | 35 | | **cgroup_inet_sock_create** | **cgroup_sock_ops** | 36 | | **cgroup_device** | **cgroup_inet4_bind** | **cgroup_inet6_bind** | 37 | | **cgroup_inet4_post_bind** | **cgroup_inet6_post_bind** | 38 | | **cgroup_inet4_connect** | **cgroup_inet6_connect** | 39 | | **cgroup_unix_connect** | **cgroup_inet4_getpeername** | 40 | | **cgroup_inet6_getpeername** | **cgroup_unix_getpeername** | 41 | | **cgroup_inet4_getsockname** | **cgroup_inet6_getsockname** | 42 | | **cgroup_unix_getsockname** | **cgroup_udp4_sendmsg** | 43 | | **cgroup_udp6_sendmsg** | **cgroup_unix_sendmsg** | 44 | | **cgroup_udp4_recvmsg** | **cgroup_udp6_recvmsg** | 45 | | **cgroup_unix_recvmsg** | **cgroup_sysctl** | 46 | | **cgroup_getsockopt** | **cgroup_setsockopt** | 47 | | **cgroup_inet_sock_release** } 48 | | *ATTACH_FLAGS* := { **multi** | **override** } 49 | 50 | DESCRIPTION 51 | =========== 52 | bpftool cgroup { show | list } *CGROUP* [effective] 53 | List all programs attached to the cgroup *CGROUP*. 54 | 55 | Output will start with program ID followed by attach type, attach flags and 56 | program name. 57 | 58 | If **effective** is specified retrieve effective programs that will execute 59 | for events within a cgroup. This includes inherited along with attached 60 | ones. 61 | 62 | bpftool cgroup tree [*CGROUP_ROOT*] [effective] 63 | Iterate over all cgroups in *CGROUP_ROOT* and list all attached programs. 64 | If *CGROUP_ROOT* is not specified, bpftool uses cgroup v2 mountpoint. 65 | 66 | The output is similar to the output of cgroup show/list commands: it starts 67 | with absolute cgroup path, followed by program ID, attach type, attach 68 | flags and program name. 69 | 70 | If **effective** is specified retrieve effective programs that will execute 71 | for events within a cgroup. This includes inherited along with attached 72 | ones. 73 | 74 | bpftool cgroup attach *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] 75 | Attach program *PROG* to the cgroup *CGROUP* with attach type *ATTACH_TYPE* 76 | and optional *ATTACH_FLAGS*. 77 | 78 | *ATTACH_FLAGS* can be one of: **override** if a sub-cgroup installs some 79 | bpf program, the program in this cgroup yields to sub-cgroup program; 80 | **multi** if a sub-cgroup installs some bpf program, that cgroup program 81 | gets run in addition to the program in this cgroup. 82 | 83 | Only one program is allowed to be attached to a cgroup with no attach flags 84 | or the **override** flag. Attaching another program will release old 85 | program and attach the new one. 86 | 87 | Multiple programs are allowed to be attached to a cgroup with **multi**. 88 | They are executed in FIFO order (those that were attached first, run 89 | first). 90 | 91 | Non-default *ATTACH_FLAGS* are supported by kernel version 4.14 and later. 92 | 93 | *ATTACH_TYPE* can be one of: 94 | 95 | - **ingress** ingress path of the inet socket (since 4.10) 96 | - **egress** egress path of the inet socket (since 4.10) 97 | - **sock_create** opening of an inet socket (since 4.10) 98 | - **sock_ops** various socket operations (since 4.12) 99 | - **device** device access (since 4.15) 100 | - **bind4** call to bind(2) for an inet4 socket (since 4.17) 101 | - **bind6** call to bind(2) for an inet6 socket (since 4.17) 102 | - **post_bind4** return from bind(2) for an inet4 socket (since 4.17) 103 | - **post_bind6** return from bind(2) for an inet6 socket (since 4.17) 104 | - **connect4** call to connect(2) for an inet4 socket (since 4.17) 105 | - **connect6** call to connect(2) for an inet6 socket (since 4.17) 106 | - **connect_unix** call to connect(2) for a unix socket (since 6.7) 107 | - **sendmsg4** call to sendto(2), sendmsg(2), sendmmsg(2) for an unconnected udp4 socket (since 4.18) 108 | - **sendmsg6** call to sendto(2), sendmsg(2), sendmmsg(2) for an unconnected udp6 socket (since 4.18) 109 | - **sendmsg_unix** call to sendto(2), sendmsg(2), sendmmsg(2) for an unconnected unix socket (since 6.7) 110 | - **recvmsg4** call to recvfrom(2), recvmsg(2), recvmmsg(2) for an unconnected udp4 socket (since 5.2) 111 | - **recvmsg6** call to recvfrom(2), recvmsg(2), recvmmsg(2) for an unconnected udp6 socket (since 5.2) 112 | - **recvmsg_unix** call to recvfrom(2), recvmsg(2), recvmmsg(2) for an unconnected unix socket (since 6.7) 113 | - **sysctl** sysctl access (since 5.2) 114 | - **getsockopt** call to getsockopt (since 5.3) 115 | - **setsockopt** call to setsockopt (since 5.3) 116 | - **getpeername4** call to getpeername(2) for an inet4 socket (since 5.8) 117 | - **getpeername6** call to getpeername(2) for an inet6 socket (since 5.8) 118 | - **getpeername_unix** call to getpeername(2) for a unix socket (since 6.7) 119 | - **getsockname4** call to getsockname(2) for an inet4 socket (since 5.8) 120 | - **getsockname6** call to getsockname(2) for an inet6 socket (since 5.8) 121 | - **getsockname_unix** call to getsockname(2) for a unix socket (since 6.7) 122 | - **sock_release** closing a userspace inet socket (since 5.9) 123 | 124 | bpftool cgroup detach *CGROUP* *ATTACH_TYPE* *PROG* 125 | Detach *PROG* from the cgroup *CGROUP* and attach type *ATTACH_TYPE*. 126 | 127 | bpftool prog help 128 | Print short help message. 129 | 130 | OPTIONS 131 | ======= 132 | .. include:: common_options.rst 133 | 134 | -f, --bpffs 135 | Show file names of pinned programs. 136 | 137 | EXAMPLES 138 | ======== 139 | | 140 | | **# mount -t bpf none /sys/fs/bpf/** 141 | | **# mkdir /sys/fs/cgroup/test.slice** 142 | | **# bpftool prog load ./device_cgroup.o /sys/fs/bpf/prog** 143 | | **# bpftool cgroup attach /sys/fs/cgroup/test.slice/ device id 1 allow_multi** 144 | 145 | **# bpftool cgroup list /sys/fs/cgroup/test.slice/** 146 | 147 | :: 148 | 149 | ID AttachType AttachFlags Name 150 | 1 device allow_multi bpf_prog1 151 | 152 | | 153 | | **# bpftool cgroup detach /sys/fs/cgroup/test.slice/ device id 1** 154 | | **# bpftool cgroup list /sys/fs/cgroup/test.slice/** 155 | 156 | :: 157 | 158 | ID AttachType AttachFlags Name 159 | -------------------------------------------------------------------------------- /docs/bpftool-feature.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | =============== 4 | bpftool-feature 5 | =============== 6 | ------------------------------------------------------------------------------- 7 | tool for inspection of eBPF-related parameters for Linux kernel or net device 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **feature** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| } 20 | 21 | *COMMANDS* := { **probe** | **help** } 22 | 23 | FEATURE COMMANDS 24 | ================ 25 | 26 | | **bpftool** **feature probe** [*COMPONENT*] [**full**] [**unprivileged**] [**macros** [**prefix** *PREFIX*]] 27 | | **bpftool** **feature list_builtins** *GROUP* 28 | | **bpftool** **feature help** 29 | | 30 | | *COMPONENT* := { **kernel** | **dev** *NAME* } 31 | | *GROUP* := { **prog_types** | **map_types** | **attach_types** | **link_types** | **helpers** } 32 | 33 | DESCRIPTION 34 | =========== 35 | bpftool feature probe [kernel] [full] [macros [prefix *PREFIX*]] 36 | Probe the running kernel and dump a number of eBPF-related parameters, such 37 | as availability of the **bpf**\ () system call, JIT status, eBPF program 38 | types availability, eBPF helper functions availability, and more. 39 | 40 | By default, bpftool **does not run probes** for **bpf_probe_write_user**\ 41 | () and **bpf_trace_printk**\() helpers which print warnings to kernel logs. 42 | To enable them and run all probes, the **full** keyword should be used. 43 | 44 | If the **macros** keyword (but not the **-j** option) is passed, a subset 45 | of the output is dumped as a list of **#define** macros that are ready to 46 | be included in a C header file, for example. If, additionally, **prefix** 47 | is used to define a *PREFIX*, the provided string will be used as a prefix 48 | to the names of the macros: this can be used to avoid conflicts on macro 49 | names when including the output of this command as a header file. 50 | 51 | Keyword **kernel** can be omitted. If no probe target is specified, probing 52 | the kernel is the default behaviour. 53 | 54 | When the **unprivileged** keyword is used, bpftool will dump only the 55 | features available to a user who does not have the **CAP_SYS_ADMIN** 56 | capability set. The features available in that case usually represent a 57 | small subset of the parameters supported by the system. Unprivileged users 58 | MUST use the **unprivileged** keyword: This is to avoid misdetection if 59 | bpftool is inadvertently run as non-root, for example. This keyword is 60 | unavailable if bpftool was compiled without libcap. 61 | 62 | bpftool feature probe dev *NAME* [full] [macros [prefix *PREFIX*]] 63 | Probe network device for supported eBPF features and dump results to the 64 | console. 65 | 66 | The keywords **full**, **macros** and **prefix** have the same role as when 67 | probing the kernel. 68 | 69 | bpftool feature list_builtins *GROUP* 70 | List items known to bpftool. These can be BPF program types 71 | (**prog_types**), BPF map types (**map_types**), attach types 72 | (**attach_types**), link types (**link_types**), or BPF helper functions 73 | (**helpers**). The command does not probe the system, but simply lists the 74 | elements that bpftool knows from compilation time, as provided from libbpf 75 | (for all object types) or from the BPF UAPI header (list of helpers). This 76 | can be used in scripts to iterate over BPF types or helpers. 77 | 78 | bpftool feature help 79 | Print short help message. 80 | 81 | OPTIONS 82 | ======= 83 | .. include:: common_options.rst 84 | -------------------------------------------------------------------------------- /docs/bpftool-iter.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ============ 4 | bpftool-iter 5 | ============ 6 | ------------------------------------------------------------------------------- 7 | tool to create BPF iterators 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **iter** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| } 20 | 21 | *COMMANDS* := { **pin** | **help** } 22 | 23 | ITER COMMANDS 24 | ============= 25 | 26 | | **bpftool** **iter pin** *OBJ* *PATH* [**map** *MAP*] 27 | | **bpftool** **iter help** 28 | | 29 | | *OBJ* := /a/file/of/bpf_iter_target.o 30 | | *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } 31 | 32 | DESCRIPTION 33 | =========== 34 | bpftool iter pin *OBJ* *PATH* [map *MAP*] 35 | A bpf iterator combines a kernel iterating of particular kernel data (e.g., 36 | tasks, bpf_maps, etc.) and a bpf program called for each kernel data object 37 | (e.g., one task, one bpf_map, etc.). User space can *read* kernel iterator 38 | output through *read()* syscall. 39 | 40 | The *pin* command creates a bpf iterator from *OBJ*, and pin it to *PATH*. 41 | The *PATH* should be located in *bpffs* mount. It must not contain a dot 42 | character ('.'), which is reserved for future extensions of *bpffs*. 43 | 44 | Map element bpf iterator requires an additional parameter *MAP* so bpf 45 | program can iterate over map elements for that map. User can have a bpf 46 | program in kernel to run with each map element, do checking, filtering, 47 | aggregation, etc. without copying data to user space. 48 | 49 | User can then *cat PATH* to see the bpf iterator output. 50 | 51 | bpftool iter help 52 | Print short help message. 53 | 54 | OPTIONS 55 | ======= 56 | .. include:: common_options.rst 57 | 58 | EXAMPLES 59 | ======== 60 | **# bpftool iter pin bpf_iter_netlink.o /sys/fs/bpf/my_netlink** 61 | 62 | :: 63 | 64 | Create a file-based bpf iterator from bpf_iter_netlink.o and pin it 65 | to /sys/fs/bpf/my_netlink 66 | 67 | **# bpftool iter pin bpf_iter_hashmap.o /sys/fs/bpf/my_hashmap map id 20** 68 | 69 | :: 70 | 71 | Create a file-based bpf iterator from bpf_iter_hashmap.o and map with 72 | id 20, and pin it to /sys/fs/bpf/my_hashmap 73 | -------------------------------------------------------------------------------- /docs/bpftool-link.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | bpftool-link 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection and simple manipulation of eBPF links 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **link** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| | { **-f** | **--bpffs** } | { **-n** | **--nomount** } } 20 | 21 | *COMMANDS* := { **show** | **list** | **pin** | **help** } 22 | 23 | LINK COMMANDS 24 | ============= 25 | 26 | | **bpftool** **link { show | list }** [*LINK*] 27 | | **bpftool** **link pin** *LINK* *FILE* 28 | | **bpftool** **link detach** *LINK* 29 | | **bpftool** **link help** 30 | | 31 | | *LINK* := { **id** *LINK_ID* | **pinned** *FILE* } 32 | 33 | 34 | DESCRIPTION 35 | =========== 36 | bpftool link { show | list } [*LINK*] 37 | Show information about active links. If *LINK* is specified show 38 | information only about given link, otherwise list all links currently 39 | active on the system. 40 | 41 | Output will start with link ID followed by link type and zero or more named 42 | attributes, some of which depend on type of link. 43 | 44 | Since Linux 5.8 bpftool is able to discover information about processes 45 | that hold open file descriptors (FDs) against BPF links. On such kernels 46 | bpftool will automatically emit this information as well. 47 | 48 | bpftool link pin *LINK* *FILE* 49 | Pin link *LINK* as *FILE*. 50 | 51 | Note: *FILE* must be located in *bpffs* mount. It must not contain a dot 52 | character ('.'), which is reserved for future extensions of *bpffs*. 53 | 54 | bpftool link detach *LINK* 55 | Force-detach link *LINK*. BPF link and its underlying BPF program will stay 56 | valid, but they will be detached from the respective BPF hook and BPF link 57 | will transition into a defunct state until last open file descriptor for 58 | that link is closed. 59 | 60 | bpftool link help 61 | Print short help message. 62 | 63 | OPTIONS 64 | ======= 65 | .. include:: common_options.rst 66 | 67 | -f, --bpffs 68 | When showing BPF links, show file names of pinned links. 69 | 70 | -n, --nomount 71 | Do not automatically attempt to mount any virtual file system (such as 72 | tracefs or BPF virtual file system) when necessary. 73 | 74 | EXAMPLES 75 | ======== 76 | **# bpftool link show** 77 | 78 | :: 79 | 80 | 10: cgroup prog 25 81 | cgroup_id 614 attach_type egress 82 | pids test_progs(223) 83 | 84 | **# bpftool --json --pretty link show** 85 | 86 | :: 87 | 88 | [{ 89 | "type": "cgroup", 90 | "prog_id": 25, 91 | "cgroup_id": 614, 92 | "attach_type": "egress", 93 | "pids": [{ 94 | "pid": 223, 95 | "comm": "test_progs" 96 | } 97 | ] 98 | } 99 | ] 100 | 101 | | 102 | | **# bpftool link pin id 10 /sys/fs/bpf/link** 103 | | **# ls -l /sys/fs/bpf/** 104 | 105 | :: 106 | 107 | -rw------- 1 root root 0 Apr 23 21:39 link 108 | -------------------------------------------------------------------------------- /docs/bpftool-net.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | bpftool-net 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection of networking related bpf prog attachments 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **net** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| } 20 | 21 | *COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** } 22 | 23 | NET COMMANDS 24 | ============ 25 | 26 | | **bpftool** **net** { **show** | **list** } [ **dev** *NAME* ] 27 | | **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ] 28 | | **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME* 29 | | **bpftool** **net help** 30 | | 31 | | *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* } 32 | | *ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | **xdpoffload** | **tcx_ingress** | **tcx_egress** } 33 | 34 | DESCRIPTION 35 | =========== 36 | bpftool net { show | list } [ dev *NAME* ] 37 | List bpf program attachments in the kernel networking subsystem. 38 | 39 | Currently, device driver xdp attachments, tcx, netkit and old-style tc 40 | classifier/action attachments, flow_dissector as well as netfilter 41 | attachments are implemented, i.e., for program types **BPF_PROG_TYPE_XDP**, 42 | **BPF_PROG_TYPE_SCHED_CLS**, **BPF_PROG_TYPE_SCHED_ACT**, 43 | **BPF_PROG_TYPE_FLOW_DISSECTOR**, **BPF_PROG_TYPE_NETFILTER**. 44 | 45 | For programs attached to a particular cgroup, e.g., 46 | **BPF_PROG_TYPE_CGROUP_SKB**, **BPF_PROG_TYPE_CGROUP_SOCK**, 47 | **BPF_PROG_TYPE_SOCK_OPS** and **BPF_PROG_TYPE_CGROUP_SOCK_ADDR**, users 48 | can use **bpftool cgroup** to dump cgroup attachments. For sk_{filter, skb, 49 | msg, reuseport} and lwt/seg6 bpf programs, users should consult other 50 | tools, e.g., iproute2. 51 | 52 | The current output will start with all xdp program attachments, followed by 53 | all tcx, netkit, then tc class/qdisc bpf program attachments, then 54 | flow_dissector and finally netfilter programs. Both xdp programs and 55 | tcx/netkit/tc programs are ordered based on ifindex number. If multiple bpf 56 | programs attached to the same networking device through **tc**, the order 57 | will be first all bpf programs attached to tcx, netkit, then tc classes, 58 | then all bpf programs attached to non clsact qdiscs, and finally all bpf 59 | programs attached to root and clsact qdisc. 60 | 61 | bpftool net attach *ATTACH_TYPE* *PROG* dev *NAME* [ overwrite ] 62 | Attach bpf program *PROG* to network interface *NAME* with type specified 63 | by *ATTACH_TYPE*. Previously attached bpf program can be replaced by the 64 | command used with **overwrite** option. Currently, only XDP-related modes 65 | are supported for *ATTACH_TYPE*. 66 | 67 | *ATTACH_TYPE* can be of: 68 | **xdp** - try native XDP and fallback to generic XDP if NIC driver does not support it; 69 | **xdpgeneric** - Generic XDP. runs at generic XDP hook when packet already enters receive path as skb; 70 | **xdpdrv** - Native XDP. runs earliest point in driver's receive path; 71 | **xdpoffload** - Offload XDP. runs directly on NIC on each packet reception; 72 | **tcx_ingress** - Ingress TCX. runs on ingress net traffic; 73 | **tcx_egress** - Egress TCX. runs on egress net traffic; 74 | 75 | bpftool net detach *ATTACH_TYPE* dev *NAME* 76 | Detach bpf program attached to network interface *NAME* with type specified 77 | by *ATTACH_TYPE*. To detach bpf program, same *ATTACH_TYPE* previously used 78 | for attach must be specified. Currently, only XDP-related modes are 79 | supported for *ATTACH_TYPE*. 80 | 81 | bpftool net help 82 | Print short help message. 83 | 84 | OPTIONS 85 | ======= 86 | .. include:: common_options.rst 87 | 88 | EXAMPLES 89 | ======== 90 | 91 | | **# bpftool net** 92 | 93 | :: 94 | 95 | xdp: 96 | eth0(2) driver id 198 97 | 98 | tc: 99 | eth0(2) htb name prefix_matcher.o:[cls_prefix_matcher_htb] id 111727 act [] 100 | eth0(2) clsact/ingress fbflow_icmp id 130246 act [] 101 | eth0(2) clsact/egress prefix_matcher.o:[cls_prefix_matcher_clsact] id 111726 102 | eth0(2) clsact/egress cls_fg_dscp id 108619 act [] 103 | eth0(2) clsact/egress fbflow_egress id 130245 104 | 105 | | 106 | | **# bpftool -jp net** 107 | 108 | :: 109 | 110 | [{ 111 | "xdp": [{ 112 | "devname": "eth0", 113 | "ifindex": 2, 114 | "mode": "driver", 115 | "id": 198 116 | } 117 | ], 118 | "tc": [{ 119 | "devname": "eth0", 120 | "ifindex": 2, 121 | "kind": "htb", 122 | "name": "prefix_matcher.o:[cls_prefix_matcher_htb]", 123 | "id": 111727, 124 | "act": [] 125 | },{ 126 | "devname": "eth0", 127 | "ifindex": 2, 128 | "kind": "clsact/ingress", 129 | "name": "fbflow_icmp", 130 | "id": 130246, 131 | "act": [] 132 | },{ 133 | "devname": "eth0", 134 | "ifindex": 2, 135 | "kind": "clsact/egress", 136 | "name": "prefix_matcher.o:[cls_prefix_matcher_clsact]", 137 | "id": 111726, 138 | },{ 139 | "devname": "eth0", 140 | "ifindex": 2, 141 | "kind": "clsact/egress", 142 | "name": "cls_fg_dscp", 143 | "id": 108619, 144 | "act": [] 145 | },{ 146 | "devname": "eth0", 147 | "ifindex": 2, 148 | "kind": "clsact/egress", 149 | "name": "fbflow_egress", 150 | "id": 130245, 151 | } 152 | ] 153 | } 154 | ] 155 | 156 | | 157 | | **# bpftool net attach xdpdrv id 16 dev enp6s0np0** 158 | | **# bpftool net** 159 | 160 | :: 161 | 162 | xdp: 163 | enp6s0np0(4) driver id 16 164 | 165 | | 166 | | **# bpftool net attach xdpdrv id 16 dev enp6s0np0** 167 | | **# bpftool net attach xdpdrv id 20 dev enp6s0np0 overwrite** 168 | | **# bpftool net** 169 | 170 | :: 171 | 172 | xdp: 173 | enp6s0np0(4) driver id 20 174 | 175 | | 176 | | **# bpftool net attach xdpdrv id 16 dev enp6s0np0** 177 | | **# bpftool net detach xdpdrv dev enp6s0np0** 178 | | **# bpftool net** 179 | 180 | :: 181 | 182 | xdp: 183 | 184 | | 185 | | **# bpftool net attach tcx_ingress name tc_prog dev lo** 186 | | **# bpftool net** 187 | | 188 | 189 | :: 190 | 191 | tc: 192 | lo(1) tcx/ingress tc_prog prog_id 29 193 | 194 | | 195 | | **# bpftool net attach tcx_ingress name tc_prog dev lo** 196 | | **# bpftool net detach tcx_ingress dev lo** 197 | | **# bpftool net** 198 | | 199 | 200 | :: 201 | 202 | tc: 203 | -------------------------------------------------------------------------------- /docs/bpftool-perf.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | bpftool-perf 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection of perf related bpf prog attachments 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **perf** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| } 20 | 21 | *COMMANDS* := 22 | { **show** | **list** | **help** } 23 | 24 | PERF COMMANDS 25 | ============= 26 | 27 | | **bpftool** **perf** { **show** | **list** } 28 | | **bpftool** **perf help** 29 | 30 | DESCRIPTION 31 | =========== 32 | bpftool perf { show | list } 33 | List all raw_tracepoint, tracepoint, kprobe attachment in the system. 34 | 35 | Output will start with process id and file descriptor in that process, 36 | followed by bpf program id, attachment information, and attachment point. 37 | The attachment point for raw_tracepoint/tracepoint is the trace probe name. 38 | The attachment point for k[ret]probe is either symbol name and offset, or a 39 | kernel virtual address. The attachment point for u[ret]probe is the file 40 | name and the file offset. 41 | 42 | bpftool perf help 43 | Print short help message. 44 | 45 | OPTIONS 46 | ======= 47 | .. include:: common_options.rst 48 | 49 | EXAMPLES 50 | ======== 51 | 52 | | **# bpftool perf** 53 | 54 | :: 55 | 56 | pid 21711 fd 5: prog_id 5 kprobe func __x64_sys_write offset 0 57 | pid 21765 fd 5: prog_id 7 kretprobe func __x64_sys_nanosleep offset 0 58 | pid 21767 fd 5: prog_id 8 tracepoint sys_enter_nanosleep 59 | pid 21800 fd 5: prog_id 9 uprobe filename /home/yhs/a.out offset 1159 60 | 61 | | 62 | | **# bpftool -j perf** 63 | 64 | :: 65 | 66 | [{"pid":21711,"fd":5,"prog_id":5,"fd_type":"kprobe","func":"__x64_sys_write","offset":0}, \ 67 | {"pid":21765,"fd":5,"prog_id":7,"fd_type":"kretprobe","func":"__x64_sys_nanosleep","offset":0}, \ 68 | {"pid":21767,"fd":5,"prog_id":8,"fd_type":"tracepoint","tracepoint":"sys_enter_nanosleep"}, \ 69 | {"pid":21800,"fd":5,"prog_id":9,"fd_type":"uprobe","filename":"/home/yhs/a.out","offset":1159}] 70 | -------------------------------------------------------------------------------- /docs/bpftool-struct_ops.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================== 4 | bpftool-struct_ops 5 | ================== 6 | ------------------------------------------------------------------------------- 7 | tool to register/unregister/introspect BPF struct_ops 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] **struct_ops** *COMMAND* 18 | 19 | *OPTIONS* := { |COMMON_OPTIONS| } 20 | 21 | *COMMANDS* := 22 | { **show** | **list** | **dump** | **register** | **unregister** | **help** } 23 | 24 | STRUCT_OPS COMMANDS 25 | =================== 26 | 27 | | **bpftool** **struct_ops { show | list }** [*STRUCT_OPS_MAP*] 28 | | **bpftool** **struct_ops dump** [*STRUCT_OPS_MAP*] 29 | | **bpftool** **struct_ops register** *OBJ* [*LINK_DIR*] 30 | | **bpftool** **struct_ops unregister** *STRUCT_OPS_MAP* 31 | | **bpftool** **struct_ops help** 32 | | 33 | | *STRUCT_OPS_MAP* := { **id** *STRUCT_OPS_MAP_ID* | **name** *STRUCT_OPS_MAP_NAME* } 34 | | *OBJ* := /a/file/of/bpf_struct_ops.o 35 | 36 | 37 | DESCRIPTION 38 | =========== 39 | bpftool struct_ops { show | list } [*STRUCT_OPS_MAP*] 40 | Show brief information about the struct_ops in the system. If 41 | *STRUCT_OPS_MAP* is specified, it shows information only for the given 42 | struct_ops. Otherwise, it lists all struct_ops currently existing in the 43 | system. 44 | 45 | Output will start with struct_ops map ID, followed by its map name and its 46 | struct_ops's kernel type. 47 | 48 | bpftool struct_ops dump [*STRUCT_OPS_MAP*] 49 | Dump details information about the struct_ops in the system. If 50 | *STRUCT_OPS_MAP* is specified, it dumps information only for the given 51 | struct_ops. Otherwise, it dumps all struct_ops currently existing in the 52 | system. 53 | 54 | bpftool struct_ops register *OBJ* [*LINK_DIR*] 55 | Register bpf struct_ops from *OBJ*. All struct_ops under the ELF section 56 | ".struct_ops" and ".struct_ops.link" will be registered to its kernel 57 | subsystem. For each struct_ops in the ".struct_ops.link" section, a link 58 | will be created. You can give *LINK_DIR* to provide a directory path where 59 | these links will be pinned with the same name as their corresponding map 60 | name. 61 | 62 | bpftool struct_ops unregister *STRUCT_OPS_MAP* 63 | Unregister the *STRUCT_OPS_MAP* from the kernel subsystem. 64 | 65 | bpftool struct_ops help 66 | Print short help message. 67 | 68 | OPTIONS 69 | ======= 70 | .. include:: common_options.rst 71 | 72 | EXAMPLES 73 | ======== 74 | **# bpftool struct_ops show** 75 | 76 | :: 77 | 78 | 100: dctcp tcp_congestion_ops 79 | 105: cubic tcp_congestion_ops 80 | 81 | **# bpftool struct_ops unregister id 105** 82 | 83 | :: 84 | 85 | Unregistered tcp_congestion_ops cubic id 105 86 | 87 | **# bpftool struct_ops register bpf_cubic.o** 88 | 89 | :: 90 | 91 | Registered tcp_congestion_ops cubic id 110 92 | -------------------------------------------------------------------------------- /docs/bpftool.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ================ 4 | BPFTOOL 5 | ================ 6 | ------------------------------------------------------------------------------- 7 | tool for inspection and simple manipulation of eBPF programs and maps 8 | ------------------------------------------------------------------------------- 9 | 10 | :Manual section: 8 11 | 12 | .. include:: substitutions.rst 13 | 14 | SYNOPSIS 15 | ======== 16 | 17 | **bpftool** [*OPTIONS*] *OBJECT* { *COMMAND* | **help** } 18 | 19 | **bpftool** **batch file** *FILE* 20 | 21 | **bpftool** **version** 22 | 23 | *OBJECT* := { **map** | **prog** | **link** | **cgroup** | **perf** | **net** | **feature** | 24 | **btf** | **gen** | **struct_ops** | **iter** } 25 | 26 | *OPTIONS* := { { **-V** | **--version** } | |COMMON_OPTIONS| } 27 | 28 | *MAP-COMMANDS* := 29 | { **show** | **list** | **create** | **dump** | **update** | **lookup** | **getnext** | 30 | **delete** | **pin** | **event_pipe** | **help** } 31 | 32 | *PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin** | 33 | **load** | **attach** | **detach** | **help** } 34 | 35 | *LINK-COMMANDS* := { **show** | **list** | **pin** | **detach** | **help** } 36 | 37 | *CGROUP-COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** } 38 | 39 | *PERF-COMMANDS* := { **show** | **list** | **help** } 40 | 41 | *NET-COMMANDS* := { **show** | **list** | **help** } 42 | 43 | *FEATURE-COMMANDS* := { **probe** | **help** } 44 | 45 | *BTF-COMMANDS* := { **show** | **list** | **dump** | **help** } 46 | 47 | *GEN-COMMANDS* := { **object** | **skeleton** | **min_core_btf** | **help** } 48 | 49 | *STRUCT-OPS-COMMANDS* := { **show** | **list** | **dump** | **register** | **unregister** | **help** } 50 | 51 | *ITER-COMMANDS* := { **pin** | **help** } 52 | 53 | DESCRIPTION 54 | =========== 55 | *bpftool* allows for inspection and simple modification of BPF objects on the 56 | system. 57 | 58 | Note that format of the output of all tools is not guaranteed to be stable and 59 | should not be depended upon. 60 | 61 | OPTIONS 62 | ======= 63 | .. include:: common_options.rst 64 | 65 | -m, --mapcompat 66 | Allow loading maps with unknown map definitions. 67 | 68 | -n, --nomount 69 | Do not automatically attempt to mount any virtual file system (such as 70 | tracefs or BPF virtual file system) when necessary. 71 | -------------------------------------------------------------------------------- /docs/common_options.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | -h, --help 4 | Print short help message (similar to **bpftool help**). 5 | 6 | -V, --version 7 | Print bpftool's version number (similar to **bpftool version**), the number 8 | of the libbpf version in use, and optional features that were included when 9 | bpftool was compiled. Optional features include linking against LLVM or 10 | libbfd to provide the disassembler for JIT-ted programs (**bpftool prog 11 | dump jited**) and usage of BPF skeletons (some features like **bpftool prog 12 | profile** or showing pids associated to BPF objects may rely on it). 13 | 14 | -j, --json 15 | Generate JSON output. For commands that cannot produce JSON, this option 16 | has no effect. 17 | 18 | -p, --pretty 19 | Generate human-readable JSON output. Implies **-j**. 20 | 21 | -d, --debug 22 | Print all logs available, even debug-level information. This includes logs 23 | from libbpf as well as from the verifier, when attempting to load programs. 24 | -------------------------------------------------------------------------------- /docs/substitutions.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | .. |COMMON_OPTIONS| replace:: { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-d** | **--debug** } 4 | -------------------------------------------------------------------------------- /include/linux/bitops.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef _LINUX_BITOPS_H_ 4 | #define _LINUX_BITOPS_H_ 5 | 6 | #ifndef BITS_PER_LONG 7 | # define BITS_PER_LONG __WORDSIZE 8 | #endif 9 | 10 | #define BITS_PER_BYTE 8 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/linux/build_bug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef _LINUX_BUILD_BUG_H 4 | #define _LINUX_BUILD_BUG_H 5 | 6 | #include 7 | 8 | /* 9 | * Force a compilation error if condition is true, but also produce a 10 | * result (of value 0 and type int), so the expression can be used 11 | * e.g. in a structure initializer (or where-ever else comma expressions 12 | * aren't permitted). 13 | */ 14 | #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); }))) 15 | 16 | /** 17 | * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied 18 | * error message. 19 | * @condition: the condition which the compiler should know is false. 20 | * 21 | * See BUILD_BUG_ON for description. 22 | */ 23 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) 24 | 25 | /** 26 | * BUILD_BUG_ON - break compile if a condition is true. 27 | * @condition: the condition which the compiler should know is false. 28 | * 29 | * If you have some code which relies on certain constants being equal, or 30 | * some other compile-time-evaluated condition, you should use BUILD_BUG_ON to 31 | * detect if someone changes it. 32 | */ 33 | #define BUILD_BUG_ON(condition) \ 34 | BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) 35 | 36 | /** 37 | * BUILD_BUG - break compile if used. 38 | * 39 | * If you have some code that you expect the compiler to eliminate at 40 | * build time, you should use BUILD_BUG to detect if it is 41 | * unexpectedly used. 42 | */ 43 | #define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/linux/compiler-gcc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef _LINUX_COMPILER_H_ 4 | #error "Please don't include directly, include instead." 5 | #endif 6 | 7 | /* 8 | * Common definitions for all gcc versions go here. 9 | */ 10 | #ifndef GCC_VERSION 11 | #define GCC_VERSION (__GNUC__ * 10000 \ 12 | + __GNUC_MINOR__ * 100 \ 13 | + __GNUC_PATCHLEVEL__) 14 | #endif 15 | 16 | #if __has_attribute(__fallthrough__) 17 | # define fallthrough __attribute__((__fallthrough__)) 18 | #else 19 | # define fallthrough do {} while (0) /* fallthrough */ 20 | #endif 21 | 22 | #if __has_attribute(__error__) 23 | # define __compiletime_error(message) __attribute__((error(message))) 24 | #endif 25 | 26 | /* &a[0] degrades to a pointer: a different type from an array */ 27 | #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) 28 | #ifndef __noreturn 29 | #define __noreturn __attribute__((noreturn)) 30 | #endif 31 | #define __printf(a, b) __attribute__((format(printf, a, b))) 32 | -------------------------------------------------------------------------------- /include/linux/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef _LINUX_COMPILER_H_ 4 | #define _LINUX_COMPILER_H_ 5 | 6 | #include 7 | 8 | #if defined(__OPTIMIZE__) && __has_attribute(__error__) 9 | # define __compiletime_assert(condition, msg, prefix, suffix) \ 10 | do { \ 11 | extern void prefix ## suffix(void) __compiletime_error(msg); \ 12 | if (!(condition)) \ 13 | prefix ## suffix(); \ 14 | } while (0) 15 | #else 16 | # define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0) 17 | #endif 18 | 19 | #define _compiletime_assert(condition, msg, prefix, suffix) \ 20 | __compiletime_assert(condition, msg, prefix, suffix) 21 | 22 | /** 23 | * compiletime_assert - break build and emit msg if condition is false 24 | * @condition: a compile-time constant condition to check 25 | * @msg: a message to emit if condition is false 26 | * 27 | * In tradition of POSIX assert, this macro will break the build if the 28 | * supplied condition is *false*, emitting the supplied error message if the 29 | * compiler has support to do so. 30 | */ 31 | #define compiletime_assert(condition, msg) \ 32 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) 33 | 34 | /* Are two types/vars the same type (ignoring qualifiers)? */ 35 | #ifndef __same_type 36 | # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) 37 | #endif 38 | 39 | #ifndef __maybe_unused 40 | # define __maybe_unused __attribute__((unused)) 41 | #endif 42 | 43 | #ifndef __weak 44 | # define __weak __attribute__((weak)) 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/linux/compiler_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_COMPILER_TYPES_H 4 | #define __LINUX_COMPILER_TYPES_H 5 | 6 | /* Compiler specific macros. */ 7 | #ifdef __GNUC__ 8 | #include 9 | #endif 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/linux/err.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_ERR_H 4 | #define __LINUX_ERR_H 5 | 6 | #include 7 | #include 8 | 9 | #define MAX_ERRNO 4095 10 | 11 | #define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) 12 | 13 | static inline void * ERR_PTR(long error_) 14 | { 15 | return (void *) error_; 16 | } 17 | 18 | static inline long PTR_ERR(const void *ptr) 19 | { 20 | return (long) ptr; 21 | } 22 | 23 | static inline bool IS_ERR(const void *ptr) 24 | { 25 | return IS_ERR_VALUE((unsigned long)ptr); 26 | } 27 | 28 | static inline bool IS_ERR_OR_NULL(const void *ptr) 29 | { 30 | return (!ptr) || IS_ERR_VALUE((unsigned long)ptr); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/linux/filter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_FILTER_H 4 | #define __LINUX_FILTER_H 5 | 6 | #include 7 | 8 | #define BPF_ALU64_IMM(OP, DST, IMM) \ 9 | ((struct bpf_insn) { \ 10 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ 11 | .dst_reg = DST, \ 12 | .src_reg = 0, \ 13 | .off = 0, \ 14 | .imm = IMM }) 15 | 16 | #define BPF_MOV64_IMM(DST, IMM) \ 17 | ((struct bpf_insn) { \ 18 | .code = BPF_ALU64 | BPF_MOV | BPF_K, \ 19 | .dst_reg = DST, \ 20 | .src_reg = 0, \ 21 | .off = 0, \ 22 | .imm = IMM }) 23 | 24 | #define BPF_EXIT_INSN() \ 25 | ((struct bpf_insn) { \ 26 | .code = BPF_JMP | BPF_EXIT, \ 27 | .dst_reg = 0, \ 28 | .src_reg = 0, \ 29 | .off = 0, \ 30 | .imm = 0 }) 31 | 32 | #define BPF_JMP_IMM(OP, DST, IMM, OFF) \ 33 | ((struct bpf_insn) { \ 34 | .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ 35 | .dst_reg = DST, \ 36 | .src_reg = 0, \ 37 | .off = OFF, \ 38 | .imm = IMM }) 39 | 40 | #define BPF_JMP32_IMM(OP, DST, IMM, OFF) \ 41 | ((struct bpf_insn) { \ 42 | .code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \ 43 | .dst_reg = DST, \ 44 | .src_reg = 0, \ 45 | .off = OFF, \ 46 | .imm = IMM }) 47 | 48 | #define BPF_JMP32_A(IMM) \ 49 | ((struct bpf_insn) { \ 50 | .code = BPF_JMP32 | BPF_JA, \ 51 | .dst_reg = 0, \ 52 | .src_reg = 0, \ 53 | .off = 0, \ 54 | .imm = IMM }) 55 | 56 | #define BPF_EMIT_CALL(FUNC) \ 57 | ((struct bpf_insn) { \ 58 | .code = BPF_JMP | BPF_CALL, \ 59 | .dst_reg = 0, \ 60 | .src_reg = 0, \ 61 | .off = 0, \ 62 | .imm = ((FUNC) - BPF_FUNC_unspec) }) 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/linux/kernel.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_KERNEL_H 4 | #define __LINUX_KERNEL_H 5 | 6 | #include 7 | 8 | #ifndef container_of 9 | #define container_of(ptr, type, member) ({ \ 10 | const typeof(((type *)0)->member) * __mptr = (ptr); \ 11 | (type *)((char *)__mptr - offsetof(type, member)); }) 12 | #endif 13 | 14 | #ifndef max 15 | #define max(x, y) ({ \ 16 | typeof(x) _max1 = (x); \ 17 | typeof(y) _max2 = (y); \ 18 | (void) (&_max1 == &_max2); \ 19 | _max1 > _max2 ? _max1 : _max2; }) 20 | #endif 21 | 22 | #ifndef roundup 23 | #define roundup(x, y) ( \ 24 | { \ 25 | const typeof(y) __y = y; \ 26 | (((x) + (__y - 1)) / __y) * __y; \ 27 | } \ 28 | ) 29 | #endif 30 | 31 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) 32 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) 33 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/linux/list.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_LIST_H 4 | #define __LINUX_LIST_H 5 | 6 | #include 7 | 8 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 9 | #define LIST_HEAD(name) \ 10 | struct list_head name = LIST_HEAD_INIT(name) 11 | 12 | #define POISON_POINTER_DELTA 0 13 | #define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) 14 | #define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) 15 | 16 | 17 | static inline void INIT_LIST_HEAD(struct list_head *list) 18 | { 19 | list->next = list; 20 | list->prev = list; 21 | } 22 | 23 | static inline void __list_add(struct list_head *new, 24 | struct list_head *prev, 25 | struct list_head *next) 26 | { 27 | next->prev = new; 28 | new->next = next; 29 | new->prev = prev; 30 | prev->next = new; 31 | } 32 | 33 | /** 34 | * list_add - add a new entry 35 | * @new: new entry to be added 36 | * @head: list head to add it after 37 | * 38 | * Insert a new entry after the specified head. 39 | * This is good for implementing stacks. 40 | */ 41 | static inline void list_add(struct list_head *new, struct list_head *head) 42 | { 43 | __list_add(new, head, head->next); 44 | } 45 | 46 | 47 | /** 48 | * list_add_tail - add a new entry 49 | * @new: new entry to be added 50 | * @head: list head to add it before 51 | * 52 | * Insert a new entry before the specified head. 53 | * This is useful for implementing queues. 54 | */ 55 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 56 | { 57 | __list_add(new, head->prev, head); 58 | } 59 | 60 | /* 61 | * Delete a list entry by making the prev/next entries 62 | * point to each other. 63 | * 64 | * This is only for internal list manipulation where we know 65 | * the prev/next entries already! 66 | */ 67 | static inline void __list_del(struct list_head * prev, struct list_head * next) 68 | { 69 | next->prev = prev; 70 | prev->next = next; 71 | } 72 | 73 | /** 74 | * list_del - deletes entry from list. 75 | * @entry: the element to delete from the list. 76 | * Note: list_empty() on entry does not return true after this, the entry is 77 | * in an undefined state. 78 | */ 79 | static inline void __list_del_entry(struct list_head *entry) 80 | { 81 | __list_del(entry->prev, entry->next); 82 | } 83 | 84 | static inline void list_del(struct list_head *entry) 85 | { 86 | __list_del(entry->prev, entry->next); 87 | entry->next = LIST_POISON1; 88 | entry->prev = LIST_POISON2; 89 | } 90 | 91 | static inline int list_empty(const struct list_head *head) 92 | { 93 | return head->next == head; 94 | } 95 | 96 | #define list_entry(ptr, type, member) \ 97 | container_of(ptr, type, member) 98 | #define list_first_entry(ptr, type, member) \ 99 | list_entry((ptr)->next, type, member) 100 | #define list_last_entry(ptr, type, member) \ 101 | list_entry((ptr)->prev, type, member) 102 | #define list_next_entry(pos, member) \ 103 | list_entry((pos)->member.next, typeof(*(pos)), member) 104 | #define list_prev_entry(pos, member) \ 105 | list_entry((pos)->member.prev, typeof(*(pos)), member) 106 | #define list_for_each_entry(pos, head, member) \ 107 | for (pos = list_first_entry(head, typeof(*pos), member); \ 108 | &pos->member != (head); \ 109 | pos = list_next_entry(pos, member)) 110 | #define list_for_each_entry_from(pos, head, member) \ 111 | for (; &pos->member != (head); \ 112 | pos = list_next_entry(pos, member)) 113 | #define list_for_each_entry_safe(pos, n, head, member) \ 114 | for (pos = list_first_entry(head, typeof(*pos), member), \ 115 | n = list_next_entry(pos, member); \ 116 | &pos->member != (head); \ 117 | pos = n, n = list_next_entry(n, member)) 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /include/linux/sizes.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_SIZES_H__ 4 | #define __LINUX_SIZES_H__ 5 | 6 | #define SZ_32K 0x00008000 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/linux/stringify.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_STRINGIFY_H 4 | #define __LINUX_STRINGIFY_H 5 | 6 | /* Indirect stringification. Doing two levels allows the parameter to be a 7 | * macro itself. For example, compile with -DFOO=bar, __stringify(FOO) 8 | * converts to "bar". 9 | */ 10 | 11 | #define __stringify_1(x...) #x 12 | #define __stringify(x...) __stringify_1(x) 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/linux/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | 3 | #ifndef __LINUX_TYPES_H 4 | #define __LINUX_TYPES_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | typedef uint64_t u64; 14 | typedef __u32 u32; 15 | typedef __u16 u16; 16 | typedef __u8 u8; 17 | 18 | #define __bitwise__ 19 | #define __bitwise __bitwise__ 20 | 21 | typedef __u16 __bitwise __le16; 22 | typedef __u16 __bitwise __be16; 23 | typedef __u32 __bitwise __le32; 24 | typedef __u32 __bitwise __be32; 25 | typedef __u64 __bitwise __le64; 26 | typedef __u64 __bitwise __be64; 27 | 28 | #ifndef __aligned_u64 29 | # define __aligned_u64 __u64 __attribute__((aligned(8))) 30 | #endif 31 | 32 | struct list_head { 33 | struct list_head *next, *prev; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/tools/dis-asm-compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ 2 | #ifndef _TOOLS_DIS_ASM_COMPAT_H 3 | #define _TOOLS_DIS_ASM_COMPAT_H 4 | 5 | #include 6 | #include 7 | 8 | /* define types for older binutils version, to centralize ifdef'ery a bit */ 9 | #ifndef DISASM_INIT_STYLED 10 | enum disassembler_style {DISASSEMBLER_STYLE_NOT_EMPTY}; 11 | typedef int (*fprintf_styled_ftype) (void *, enum disassembler_style, const char*, ...); 12 | #endif 13 | 14 | /* 15 | * Trivial fprintf wrapper to be used as the fprintf_styled_func argument to 16 | * init_disassemble_info_compat() when normal fprintf suffices. 17 | */ 18 | static inline int fprintf_styled(void *out, 19 | enum disassembler_style style, 20 | const char *fmt, ...) 21 | { 22 | va_list args; 23 | int r; 24 | 25 | (void)style; 26 | 27 | va_start(args, fmt); 28 | r = vfprintf(out, fmt, args); 29 | va_end(args); 30 | 31 | return r; 32 | } 33 | 34 | /* 35 | * Wrapper for init_disassemble_info() that hides version 36 | * differences. Depending on binutils version and architecture either 37 | * fprintf_func or fprintf_styled_func will be called. 38 | */ 39 | static inline void init_disassemble_info_compat(struct disassemble_info *info, 40 | void *stream, 41 | fprintf_ftype unstyled_func, 42 | fprintf_styled_ftype styled_func) 43 | { 44 | #ifdef DISASM_INIT_STYLED 45 | init_disassemble_info(info, stream, 46 | unstyled_func, 47 | styled_func); 48 | #else 49 | (void)styled_func; 50 | init_disassemble_info(info, stream, 51 | unstyled_func); 52 | #endif 53 | } 54 | 55 | #endif /* _TOOLS_DIS_ASM_COMPAT_H */ 56 | -------------------------------------------------------------------------------- /include/uapi/asm-generic/bitsperlong.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _UAPI__ASM_GENERIC_BITS_PER_LONG 3 | #define _UAPI__ASM_GENERIC_BITS_PER_LONG 4 | 5 | #ifndef __BITS_PER_LONG 6 | /* 7 | * In order to keep safe and avoid regression, only unify uapi 8 | * bitsperlong.h for some archs which are using newer toolchains 9 | * that have the definitions of __CHAR_BIT__ and __SIZEOF_LONG__. 10 | * See the following link for more info: 11 | * https://lore.kernel.org/linux-arch/b9624545-2c80-49a1-ac3c-39264a591f7b@app.fastmail.com/ 12 | */ 13 | #if defined(__CHAR_BIT__) && defined(__SIZEOF_LONG__) 14 | #define __BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__) 15 | #else 16 | /* 17 | * There seems to be no way of detecting this automatically from user 18 | * space, so 64 bit architectures should override this in their 19 | * bitsperlong.h. In particular, an architecture that supports 20 | * both 32 and 64 bit user space must not rely on CONFIG_64BIT 21 | * to decide it, but rather check a compiler provided macro. 22 | */ 23 | #define __BITS_PER_LONG 32 24 | #endif 25 | #endif 26 | 27 | #ifndef __BITS_PER_LONG_LONG 28 | #define __BITS_PER_LONG_LONG 64 29 | #endif 30 | 31 | #endif /* _UAPI__ASM_GENERIC_BITS_PER_LONG */ 32 | -------------------------------------------------------------------------------- /include/uapi/linux/bpf_common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _UAPI__LINUX_BPF_COMMON_H__ 3 | #define _UAPI__LINUX_BPF_COMMON_H__ 4 | 5 | /* Instruction classes */ 6 | #define BPF_CLASS(code) ((code) & 0x07) 7 | #define BPF_LD 0x00 8 | #define BPF_LDX 0x01 9 | #define BPF_ST 0x02 10 | #define BPF_STX 0x03 11 | #define BPF_ALU 0x04 12 | #define BPF_JMP 0x05 13 | #define BPF_RET 0x06 14 | #define BPF_MISC 0x07 15 | 16 | /* ld/ldx fields */ 17 | #define BPF_SIZE(code) ((code) & 0x18) 18 | #define BPF_W 0x00 /* 32-bit */ 19 | #define BPF_H 0x08 /* 16-bit */ 20 | #define BPF_B 0x10 /* 8-bit */ 21 | /* eBPF BPF_DW 0x18 64-bit */ 22 | #define BPF_MODE(code) ((code) & 0xe0) 23 | #define BPF_IMM 0x00 24 | #define BPF_ABS 0x20 25 | #define BPF_IND 0x40 26 | #define BPF_MEM 0x60 27 | #define BPF_LEN 0x80 28 | #define BPF_MSH 0xa0 29 | 30 | /* alu/jmp fields */ 31 | #define BPF_OP(code) ((code) & 0xf0) 32 | #define BPF_ADD 0x00 33 | #define BPF_SUB 0x10 34 | #define BPF_MUL 0x20 35 | #define BPF_DIV 0x30 36 | #define BPF_OR 0x40 37 | #define BPF_AND 0x50 38 | #define BPF_LSH 0x60 39 | #define BPF_RSH 0x70 40 | #define BPF_NEG 0x80 41 | #define BPF_MOD 0x90 42 | #define BPF_XOR 0xa0 43 | 44 | #define BPF_JA 0x00 45 | #define BPF_JEQ 0x10 46 | #define BPF_JGT 0x20 47 | #define BPF_JGE 0x30 48 | #define BPF_JSET 0x40 49 | #define BPF_SRC(code) ((code) & 0x08) 50 | #define BPF_K 0x00 51 | #define BPF_X 0x08 52 | 53 | #ifndef BPF_MAXINSNS 54 | #define BPF_MAXINSNS 4096 55 | #endif 56 | 57 | #endif /* _UAPI__LINUX_BPF_COMMON_H__ */ 58 | -------------------------------------------------------------------------------- /include/uapi/linux/btf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (c) 2018 Facebook */ 3 | #ifndef _UAPI__LINUX_BTF_H__ 4 | #define _UAPI__LINUX_BTF_H__ 5 | 6 | #include 7 | 8 | #define BTF_MAGIC 0xeB9F 9 | #define BTF_VERSION 1 10 | 11 | struct btf_header { 12 | __u16 magic; 13 | __u8 version; 14 | __u8 flags; 15 | __u32 hdr_len; 16 | 17 | /* All offsets are in bytes relative to the end of this header */ 18 | __u32 type_off; /* offset of type section */ 19 | __u32 type_len; /* length of type section */ 20 | __u32 str_off; /* offset of string section */ 21 | __u32 str_len; /* length of string section */ 22 | }; 23 | 24 | /* Max # of type identifier */ 25 | #define BTF_MAX_TYPE 0x000fffff 26 | /* Max offset into the string section */ 27 | #define BTF_MAX_NAME_OFFSET 0x00ffffff 28 | /* Max # of struct/union/enum members or func args */ 29 | #define BTF_MAX_VLEN 0xffff 30 | 31 | struct btf_type { 32 | __u32 name_off; 33 | /* "info" bits arrangement 34 | * bits 0-15: vlen (e.g. # of struct's members) 35 | * bits 16-23: unused 36 | * bits 24-28: kind (e.g. int, ptr, array...etc) 37 | * bits 29-30: unused 38 | * bit 31: kind_flag, currently used by 39 | * struct, union, enum, fwd, enum64, 40 | * decl_tag and type_tag 41 | */ 42 | __u32 info; 43 | /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64. 44 | * "size" tells the size of the type it is describing. 45 | * 46 | * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, 47 | * FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG. 48 | * "type" is a type_id referring to another type. 49 | */ 50 | union { 51 | __u32 size; 52 | __u32 type; 53 | }; 54 | }; 55 | 56 | #define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f) 57 | #define BTF_INFO_VLEN(info) ((info) & 0xffff) 58 | #define BTF_INFO_KFLAG(info) ((info) >> 31) 59 | 60 | enum { 61 | BTF_KIND_UNKN = 0, /* Unknown */ 62 | BTF_KIND_INT = 1, /* Integer */ 63 | BTF_KIND_PTR = 2, /* Pointer */ 64 | BTF_KIND_ARRAY = 3, /* Array */ 65 | BTF_KIND_STRUCT = 4, /* Struct */ 66 | BTF_KIND_UNION = 5, /* Union */ 67 | BTF_KIND_ENUM = 6, /* Enumeration up to 32-bit values */ 68 | BTF_KIND_FWD = 7, /* Forward */ 69 | BTF_KIND_TYPEDEF = 8, /* Typedef */ 70 | BTF_KIND_VOLATILE = 9, /* Volatile */ 71 | BTF_KIND_CONST = 10, /* Const */ 72 | BTF_KIND_RESTRICT = 11, /* Restrict */ 73 | BTF_KIND_FUNC = 12, /* Function */ 74 | BTF_KIND_FUNC_PROTO = 13, /* Function Proto */ 75 | BTF_KIND_VAR = 14, /* Variable */ 76 | BTF_KIND_DATASEC = 15, /* Section */ 77 | BTF_KIND_FLOAT = 16, /* Floating point */ 78 | BTF_KIND_DECL_TAG = 17, /* Decl Tag */ 79 | BTF_KIND_TYPE_TAG = 18, /* Type Tag */ 80 | BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */ 81 | 82 | NR_BTF_KINDS, 83 | BTF_KIND_MAX = NR_BTF_KINDS - 1, 84 | }; 85 | 86 | /* For some specific BTF_KIND, "struct btf_type" is immediately 87 | * followed by extra data. 88 | */ 89 | 90 | /* BTF_KIND_INT is followed by a u32 and the following 91 | * is the 32 bits arrangement: 92 | */ 93 | #define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24) 94 | #define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16) 95 | #define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff) 96 | 97 | /* Attributes stored in the BTF_INT_ENCODING */ 98 | #define BTF_INT_SIGNED (1 << 0) 99 | #define BTF_INT_CHAR (1 << 1) 100 | #define BTF_INT_BOOL (1 << 2) 101 | 102 | /* BTF_KIND_ENUM is followed by multiple "struct btf_enum". 103 | * The exact number of btf_enum is stored in the vlen (of the 104 | * info in "struct btf_type"). 105 | */ 106 | struct btf_enum { 107 | __u32 name_off; 108 | __s32 val; 109 | }; 110 | 111 | /* BTF_KIND_ARRAY is followed by one "struct btf_array" */ 112 | struct btf_array { 113 | __u32 type; 114 | __u32 index_type; 115 | __u32 nelems; 116 | }; 117 | 118 | /* BTF_KIND_STRUCT and BTF_KIND_UNION are followed 119 | * by multiple "struct btf_member". The exact number 120 | * of btf_member is stored in the vlen (of the info in 121 | * "struct btf_type"). 122 | */ 123 | struct btf_member { 124 | __u32 name_off; 125 | __u32 type; 126 | /* If the type info kind_flag is set, the btf_member offset 127 | * contains both member bitfield size and bit offset. The 128 | * bitfield size is set for bitfield members. If the type 129 | * info kind_flag is not set, the offset contains only bit 130 | * offset. 131 | */ 132 | __u32 offset; 133 | }; 134 | 135 | /* If the struct/union type info kind_flag is set, the 136 | * following two macros are used to access bitfield_size 137 | * and bit_offset from btf_member.offset. 138 | */ 139 | #define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24) 140 | #define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff) 141 | 142 | /* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param". 143 | * The exact number of btf_param is stored in the vlen (of the 144 | * info in "struct btf_type"). 145 | */ 146 | struct btf_param { 147 | __u32 name_off; 148 | __u32 type; 149 | }; 150 | 151 | enum { 152 | BTF_VAR_STATIC = 0, 153 | BTF_VAR_GLOBAL_ALLOCATED = 1, 154 | BTF_VAR_GLOBAL_EXTERN = 2, 155 | }; 156 | 157 | enum btf_func_linkage { 158 | BTF_FUNC_STATIC = 0, 159 | BTF_FUNC_GLOBAL = 1, 160 | BTF_FUNC_EXTERN = 2, 161 | }; 162 | 163 | /* BTF_KIND_VAR is followed by a single "struct btf_var" to describe 164 | * additional information related to the variable such as its linkage. 165 | */ 166 | struct btf_var { 167 | __u32 linkage; 168 | }; 169 | 170 | /* BTF_KIND_DATASEC is followed by multiple "struct btf_var_secinfo" 171 | * to describe all BTF_KIND_VAR types it contains along with it's 172 | * in-section offset as well as size. 173 | */ 174 | struct btf_var_secinfo { 175 | __u32 type; 176 | __u32 offset; 177 | __u32 size; 178 | }; 179 | 180 | /* BTF_KIND_DECL_TAG is followed by a single "struct btf_decl_tag" to describe 181 | * additional information related to the tag applied location. 182 | * If component_idx == -1, the tag is applied to a struct, union, 183 | * variable or function. Otherwise, it is applied to a struct/union 184 | * member or a func argument, and component_idx indicates which member 185 | * or argument (0 ... vlen-1). 186 | */ 187 | struct btf_decl_tag { 188 | __s32 component_idx; 189 | }; 190 | 191 | /* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64". 192 | * The exact number of btf_enum64 is stored in the vlen (of the 193 | * info in "struct btf_type"). 194 | */ 195 | struct btf_enum64 { 196 | __u32 name_off; 197 | __u32 val_lo32; 198 | __u32 val_hi32; 199 | }; 200 | 201 | #endif /* _UAPI__LINUX_BTF_H__ */ 202 | -------------------------------------------------------------------------------- /include/uapi/linux/const.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* const.h: Macros for dealing with constants. */ 3 | 4 | #ifndef _UAPI_LINUX_CONST_H 5 | #define _UAPI_LINUX_CONST_H 6 | 7 | /* Some constant macros are used in both assembler and 8 | * C code. Therefore we cannot annotate them always with 9 | * 'UL' and other type specifiers unilaterally. We 10 | * use the following macros to deal with this. 11 | * 12 | * Similarly, _AT() will cast an expression with a type in C, but 13 | * leave it unchanged in asm. 14 | */ 15 | 16 | #ifdef __ASSEMBLY__ 17 | #define _AC(X,Y) X 18 | #define _AT(T,X) X 19 | #else 20 | #define __AC(X,Y) (X##Y) 21 | #define _AC(X,Y) __AC(X,Y) 22 | #define _AT(T,X) ((T)(X)) 23 | #endif 24 | 25 | #define _UL(x) (_AC(x, UL)) 26 | #define _ULL(x) (_AC(x, ULL)) 27 | 28 | #define _BITUL(x) (_UL(1) << (x)) 29 | #define _BITULL(x) (_ULL(1) << (x)) 30 | 31 | #if !defined(__ASSEMBLY__) 32 | /* 33 | * Missing asm support 34 | * 35 | * __BIT128() would not work in the asm code, as it shifts an 36 | * 'unsigned __int128' data type as direct representation of 37 | * 128 bit constants is not supported in the gcc compiler, as 38 | * they get silently truncated. 39 | * 40 | * TODO: Please revisit this implementation when gcc compiler 41 | * starts representing 128 bit constants directly like long 42 | * and unsigned long etc. Subsequently drop the comment for 43 | * GENMASK_U128() which would then start supporting asm code. 44 | */ 45 | #define _BIT128(x) ((unsigned __int128)(1) << (x)) 46 | #endif 47 | 48 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) 49 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) 50 | 51 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 52 | 53 | #endif /* _UAPI_LINUX_CONST_H */ 54 | -------------------------------------------------------------------------------- /include/uapi/linux/netlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _UAPI__LINUX_NETLINK_H 3 | #define _UAPI__LINUX_NETLINK_H 4 | 5 | #include 6 | #include /* for __kernel_sa_family_t */ 7 | #include 8 | 9 | #define NETLINK_ROUTE 0 /* Routing/device hook */ 10 | #define NETLINK_UNUSED 1 /* Unused number */ 11 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ 12 | #define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ 13 | #define NETLINK_SOCK_DIAG 4 /* socket monitoring */ 14 | #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ 15 | #define NETLINK_XFRM 6 /* ipsec */ 16 | #define NETLINK_SELINUX 7 /* SELinux event notifications */ 17 | #define NETLINK_ISCSI 8 /* Open-iSCSI */ 18 | #define NETLINK_AUDIT 9 /* auditing */ 19 | #define NETLINK_FIB_LOOKUP 10 20 | #define NETLINK_CONNECTOR 11 21 | #define NETLINK_NETFILTER 12 /* netfilter subsystem */ 22 | #define NETLINK_IP6_FW 13 23 | #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ 24 | #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ 25 | #define NETLINK_GENERIC 16 26 | /* leave room for NETLINK_DM (DM Events) */ 27 | #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ 28 | #define NETLINK_ECRYPTFS 19 29 | #define NETLINK_RDMA 20 30 | #define NETLINK_CRYPTO 21 /* Crypto layer */ 31 | #define NETLINK_SMC 22 /* SMC monitoring */ 32 | 33 | #define NETLINK_INET_DIAG NETLINK_SOCK_DIAG 34 | 35 | #define MAX_LINKS 32 36 | 37 | struct sockaddr_nl { 38 | __kernel_sa_family_t nl_family; /* AF_NETLINK */ 39 | unsigned short nl_pad; /* zero */ 40 | __u32 nl_pid; /* port ID */ 41 | __u32 nl_groups; /* multicast groups mask */ 42 | }; 43 | 44 | struct nlmsghdr { 45 | __u32 nlmsg_len; /* Length of message including header */ 46 | __u16 nlmsg_type; /* Message content */ 47 | __u16 nlmsg_flags; /* Additional flags */ 48 | __u32 nlmsg_seq; /* Sequence number */ 49 | __u32 nlmsg_pid; /* Sending process port ID */ 50 | }; 51 | 52 | /* Flags values */ 53 | 54 | #define NLM_F_REQUEST 0x01 /* It is request message. */ 55 | #define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */ 56 | #define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */ 57 | #define NLM_F_ECHO 0x08 /* Echo this request */ 58 | #define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */ 59 | #define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */ 60 | 61 | /* Modifiers to GET request */ 62 | #define NLM_F_ROOT 0x100 /* specify tree root */ 63 | #define NLM_F_MATCH 0x200 /* return all matching */ 64 | #define NLM_F_ATOMIC 0x400 /* atomic GET */ 65 | #define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) 66 | 67 | /* Modifiers to NEW request */ 68 | #define NLM_F_REPLACE 0x100 /* Override existing */ 69 | #define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ 70 | #define NLM_F_CREATE 0x400 /* Create, if it does not exist */ 71 | #define NLM_F_APPEND 0x800 /* Add to end of list */ 72 | 73 | /* Modifiers to DELETE request */ 74 | #define NLM_F_NONREC 0x100 /* Do not delete recursively */ 75 | 76 | /* Flags for ACK message */ 77 | #define NLM_F_CAPPED 0x100 /* request was capped */ 78 | #define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */ 79 | 80 | /* 81 | 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL 82 | 4.4BSD CHANGE NLM_F_REPLACE 83 | 84 | True CHANGE NLM_F_CREATE|NLM_F_REPLACE 85 | Append NLM_F_CREATE 86 | Check NLM_F_EXCL 87 | */ 88 | 89 | #define NLMSG_ALIGNTO 4U 90 | #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) 91 | #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) 92 | #define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN) 93 | #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) 94 | #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) 95 | #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ 96 | (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) 97 | #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ 98 | (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ 99 | (nlh)->nlmsg_len <= (len)) 100 | #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) 101 | 102 | #define NLMSG_NOOP 0x1 /* Nothing. */ 103 | #define NLMSG_ERROR 0x2 /* Error */ 104 | #define NLMSG_DONE 0x3 /* End of a dump */ 105 | #define NLMSG_OVERRUN 0x4 /* Data lost */ 106 | 107 | #define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ 108 | 109 | struct nlmsgerr { 110 | int error; 111 | struct nlmsghdr msg; 112 | /* 113 | * followed by the message contents unless NETLINK_CAP_ACK was set 114 | * or the ACK indicates success (error == 0) 115 | * message length is aligned with NLMSG_ALIGN() 116 | */ 117 | /* 118 | * followed by TLVs defined in enum nlmsgerr_attrs 119 | * if NETLINK_EXT_ACK was set 120 | */ 121 | }; 122 | 123 | /** 124 | * enum nlmsgerr_attrs - nlmsgerr attributes 125 | * @NLMSGERR_ATTR_UNUSED: unused 126 | * @NLMSGERR_ATTR_MSG: error message string (string) 127 | * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original 128 | * message, counting from the beginning of the header (u32) 129 | * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to 130 | * be used - in the success case - to identify a created 131 | * object or operation or similar (binary) 132 | * @__NLMSGERR_ATTR_MAX: number of attributes 133 | * @NLMSGERR_ATTR_MAX: highest attribute number 134 | */ 135 | enum nlmsgerr_attrs { 136 | NLMSGERR_ATTR_UNUSED, 137 | NLMSGERR_ATTR_MSG, 138 | NLMSGERR_ATTR_OFFS, 139 | NLMSGERR_ATTR_COOKIE, 140 | 141 | __NLMSGERR_ATTR_MAX, 142 | NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 143 | }; 144 | 145 | #define NETLINK_ADD_MEMBERSHIP 1 146 | #define NETLINK_DROP_MEMBERSHIP 2 147 | #define NETLINK_PKTINFO 3 148 | #define NETLINK_BROADCAST_ERROR 4 149 | #define NETLINK_NO_ENOBUFS 5 150 | #ifndef __KERNEL__ 151 | #define NETLINK_RX_RING 6 152 | #define NETLINK_TX_RING 7 153 | #endif 154 | #define NETLINK_LISTEN_ALL_NSID 8 155 | #define NETLINK_LIST_MEMBERSHIPS 9 156 | #define NETLINK_CAP_ACK 10 157 | #define NETLINK_EXT_ACK 11 158 | #define NETLINK_GET_STRICT_CHK 12 159 | 160 | struct nl_pktinfo { 161 | __u32 group; 162 | }; 163 | 164 | struct nl_mmap_req { 165 | unsigned int nm_block_size; 166 | unsigned int nm_block_nr; 167 | unsigned int nm_frame_size; 168 | unsigned int nm_frame_nr; 169 | }; 170 | 171 | struct nl_mmap_hdr { 172 | unsigned int nm_status; 173 | unsigned int nm_len; 174 | __u32 nm_group; 175 | /* credentials */ 176 | __u32 nm_pid; 177 | __u32 nm_uid; 178 | __u32 nm_gid; 179 | }; 180 | 181 | #ifndef __KERNEL__ 182 | enum nl_mmap_status { 183 | NL_MMAP_STATUS_UNUSED, 184 | NL_MMAP_STATUS_RESERVED, 185 | NL_MMAP_STATUS_VALID, 186 | NL_MMAP_STATUS_COPY, 187 | NL_MMAP_STATUS_SKIP, 188 | }; 189 | 190 | #define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO 191 | #define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) 192 | #define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) 193 | #endif 194 | 195 | #define NET_MAJOR 36 /* Major 36 is reserved for networking */ 196 | 197 | enum { 198 | NETLINK_UNCONNECTED = 0, 199 | NETLINK_CONNECTED, 200 | }; 201 | 202 | /* 203 | * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> 204 | * +---------------------+- - -+- - - - - - - - - -+- - -+ 205 | * | Header | Pad | Payload | Pad | 206 | * | (struct nlattr) | ing | | ing | 207 | * +---------------------+- - -+- - - - - - - - - -+- - -+ 208 | * <-------------- nlattr->nla_len --------------> 209 | */ 210 | 211 | struct nlattr { 212 | __u16 nla_len; 213 | __u16 nla_type; 214 | }; 215 | 216 | /* 217 | * nla_type (16 bits) 218 | * +---+---+-------------------------------+ 219 | * | N | O | Attribute Type | 220 | * +---+---+-------------------------------+ 221 | * N := Carries nested attributes 222 | * O := Payload stored in network byte order 223 | * 224 | * Note: The N and O flag are mutually exclusive. 225 | */ 226 | #define NLA_F_NESTED (1 << 15) 227 | #define NLA_F_NET_BYTEORDER (1 << 14) 228 | #define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) 229 | 230 | #define NLA_ALIGNTO 4 231 | #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) 232 | #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) 233 | 234 | /* Generic 32 bitflags attribute content sent to the kernel. 235 | * 236 | * The value is a bitmap that defines the values being set 237 | * The selector is a bitmask that defines which value is legit 238 | * 239 | * Examples: 240 | * value = 0x0, and selector = 0x1 241 | * implies we are selecting bit 1 and we want to set its value to 0. 242 | * 243 | * value = 0x2, and selector = 0x2 244 | * implies we are selecting bit 2 and we want to set its value to 1. 245 | * 246 | */ 247 | struct nla_bitfield32 { 248 | __u32 value; 249 | __u32 selector; 250 | }; 251 | 252 | #endif /* _UAPI__LINUX_NETLINK_H */ 253 | -------------------------------------------------------------------------------- /include/uapi/linux/tc_act/tc_bpf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ 2 | /* 3 | * Copyright (c) 2015 Jiri Pirko 4 | */ 5 | 6 | #ifndef __LINUX_TC_BPF_H 7 | #define __LINUX_TC_BPF_H 8 | 9 | #include 10 | 11 | struct tc_act_bpf { 12 | tc_gen; 13 | }; 14 | 15 | enum { 16 | TCA_ACT_BPF_UNSPEC, 17 | TCA_ACT_BPF_TM, 18 | TCA_ACT_BPF_PARMS, 19 | TCA_ACT_BPF_OPS_LEN, 20 | TCA_ACT_BPF_OPS, 21 | TCA_ACT_BPF_FD, 22 | TCA_ACT_BPF_NAME, 23 | TCA_ACT_BPF_PAD, 24 | TCA_ACT_BPF_TAG, 25 | TCA_ACT_BPF_ID, 26 | __TCA_ACT_BPF_MAX, 27 | }; 28 | #define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1) 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | This directory contains scripts for maintaining bpftool's GitHub mirror. 4 | 5 | ## gh-label-release-assets.sh 6 | 7 | This script can **add labels to GitHub release assets**. Labels are used in the 8 | GitHub interface instead of the file name in the list of assets, but they do 9 | not alter the download URL. 10 | 11 | The script takes the tag reference for the release as single parameter. The 12 | repository to use, and the names and labels to set for assets are currently 13 | defined in the script itself. 14 | 15 | It requires the [GitHub command line][gh] (`gh`). 16 | 17 | Note that only users with push access to the repository can update release 18 | assets and set labels. 19 | 20 | [gh]: https://cli.github.com/ 21 | 22 | ## sync-kernel.sh 23 | 24 | ### Synchronize Linux and bpftool mirror 25 | 26 | This script synchronizes the bpftool mirror with the bpftool sources (and 27 | related files) from the Linux kernel repository. 28 | 29 | Synchronization is usually performed against the `bpf-next` and `bpf` trees, 30 | because this is where most bpftool updates are merged. 31 | 32 | By default, the script does not pick the very latest commits in these trees, 33 | but instead it uses the commits referenced in the libbpf submodule. This is 34 | because bpftool strongly relies on libbpf, and the libbpf GitHub mirror is used 35 | here as a submodule dependency. This libbpf mirror is also periodically updated 36 | to the latest `bpf-next` and `bpf` tree, and records to what kernel commits it 37 | was brought up-to-date. To ensure optimal compatibility between the bpftool 38 | sources and the libbpf dependency, we want to update them to the same point of 39 | reference. 40 | 41 | ### Prerequisites 42 | 43 | There is no particular tool required for running the script, except `git` of 44 | course. 45 | 46 | However, you need a local copy of the Linux Git repository on your system 47 | in order to successfully run the script. You can set it up as follows: 48 | 49 | ```console 50 | $ git clone 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git' linux 51 | $ cd linux 52 | $ git remote rename origin bpf-next 53 | $ git branch --move master bpf-next 54 | $ git remote add bpf 'https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git' 55 | $ git fetch bpf 56 | $ git checkout bpf/master 57 | $ git switch --create bpf 58 | $ git branch --set-upstream-to bpf/master 59 | $ git switch bpf-next 60 | ``` 61 | 62 | At the end of the process, the repository should contain two branches 63 | `bpf-next` and `bpf`, pointing to the `master` branches of the `bpf-next` and 64 | `bpf` remote repositories, respectively. These two branches are required to 65 | synchronize the mirror correctly. 66 | 67 | You can later update this repository with the following commands: 68 | 69 | ```console 70 | $ git switch bpf 71 | $ git pull --set-upstream bpf master 72 | $ git switch bpf-next 73 | $ git pull --set-upstream bpf-next master 74 | ``` 75 | 76 | Also make sure you have cloned the bpftool mirror recursively, to check out the 77 | libbpf submodule. If you have not, run the following: 78 | 79 | ```console 80 | $ git submodule update --init 81 | ``` 82 | 83 | ### Usage 84 | 85 | As preliminary steps: 86 | 87 | - Make sure that you have a Linux Git repository installed (see above), with 88 | two branches `bpf-next` and `bpf` up-to-date. 89 | - Make sure your mirror repository is clean. 90 | 91 | Then run the script: 92 | 93 | ```console 94 | $ ./sync-kernel.sh 95 | ``` 96 | 97 | If working from within the bpftool repository, the path to the `` 98 | is typically the current working directory (`.`). The second argument, 99 | ``, is the path to the Linux Git repository mentioned earlier. 100 | 101 | Several environment variables can modify some internal parameters of the 102 | script: 103 | 104 | - Set `BPF_NEXT_BASELINE `to override the `bpf-next` tree commit to use (the 105 | commit from the `bpf-next` branch with which the bpftool repository is 106 | currently synchronized, prior to running the script). If unset, use the hash 107 | from `/CHECKPOINT-COMMIT` is used. 108 | - Set `BPF_BASELINE `to override the `bpf` tree commit to use (the commit from 109 | the `bpf` branch with which the bpftool repository is currently synchronized, 110 | prior to running the script). If unset, use the hash from 111 | `/BPF-CHECKPOINT-COMMIT` is used. 112 | - Set `BPF_NEXT_TIP_COMMIT` to override the `bpf-next` tree target commit (the 113 | commit in `bpf-next` up to which the bpftool mirror should be synchronized). 114 | If unset, use the hash from `/libbpf/CHECKPOINT-COMMIT`, after 115 | the libbpf repository update that takes place at the beginning of the update 116 | process. 117 | - Set `BPF_TIP_COMMIT` to override the `bpf` tree target commit (the commit in 118 | `bpf` up to which the bpftool mirror should be synchronized). If unset, use 119 | the hash from `/libbpf/BPF-CHECKPOINT-COMMIT`, after the libbpf 120 | repository update that takes place at the beginning of the update process. 121 | - Set `SKIP_LIBBPF_UPDATE` to `1` to avoid updating libbpf automatically. 122 | - Set `MANUAL_MODE` to `1` to manually control every cherry-picked commit. 123 | 124 | ### How it works 125 | 126 | This script synchronizes the bpftool mirror with upstream bpftool sources from 127 | the Linux kernel repository. 128 | 129 | It performs the following steps: 130 | 131 | - First, the script updates the libbpf submodule, commits the change, and (by 132 | default) picks up libbpf's latest checkpoints to use them as target commits 133 | for the bpftool mirror. 134 | 135 | - In the Linux repository, from the `bpf-next` branch, it creates new branches, 136 | filters out all non-bpftool-related files, and reworks the layout to 137 | replicate the layout from the bpftool mirror. 138 | 139 | - It generates patches for each commit touching `bpftool` or the required UAPI 140 | files, up to the target commit, and exports these patches to a temporary 141 | repository. 142 | 143 | - In a new branch in the bpftool mirror, the script applies (`git am`) each of 144 | these patches to the mirror. 145 | 146 | - Then the script checks out the `bpf` branch in the Linux repository, and 147 | repeats the same operations. 148 | 149 | - On top of the new patches applied to the mirror, the script creates a last 150 | commit with the updated checkpoints, using a cover letter summarizing the 151 | changes as the commit description. 152 | 153 | - The next step is verification. The script applies to the Linux repository 154 | (`bpf-next` branch) a patch containing known differences between the Linux 155 | repository and the bpftool mirror. Then it looks for remaining differences 156 | between the two repositories, and warn the user if it finds any. Patches 157 | picked up from the `bpf` tree are usually a source of differences at this 158 | step. If the patch containing the known differences is to be updated after 159 | the synchronization in progress, the user should do it at this time, before 160 | the temporary files from the script are deleted. 161 | 162 | - At last, the script cleans up the temporary files and branches in the Linux 163 | repository. Note that these temporary files and branches are not cleaned up 164 | if the script fails during execution. 165 | -------------------------------------------------------------------------------- /scripts/gh-label-release-assets.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | # Use this script to add labels to GitHub release assets for a given release. 8 | # 9 | # Based on the following console workflow: 10 | # 11 | # gh api \ 12 | # '/repos/qmonnet/bpftool/releases/tags/v7.2.0-snapshot.0' \ 13 | # --jq '.id' 14 | # gh api \ 15 | # '/repos/qmonnet/bpftool/releases/96330927/assets' \ 16 | # --jq '.[] | select(.name == "bpftool-amd64.tar.gz").id' 17 | # gh api \ 18 | # --method PATCH \ 19 | # -H "Accept: application/vnd.github+json" \ 20 | # -H "X-GitHub-Api-Version: 2022-11-28" \ 21 | # '/repos/qmonnet/bpftool/releases/assets/100280866' \ 22 | # -f name='bpftool-arm64.tar.gz' \ 23 | # -f label='Compressed binary (arm64)' 24 | 25 | REPO="libbpf/bpftool" 26 | 27 | usage() { 28 | echo "Update asset labels for bpftool releases" 29 | echo "Usage:" 30 | echo " $0 [options] " 31 | echo "" 32 | echo "OPTIONS" 33 | echo " -h display this help" 34 | exit "$1" 35 | } 36 | 37 | OPTIND=1 38 | while getopts "h" opt; do 39 | case "$opt" in 40 | h) 41 | usage 0 42 | ;; 43 | *) 44 | usage 1 45 | ;; 46 | esac 47 | done 48 | shift $((OPTIND-1)) 49 | [[ "${1:-}" = "--" ]] && shift 50 | 51 | # Get release tag from command line 52 | if [[ "$#" -lt 1 ]]; then 53 | echo "error: missing release tag" 54 | usage 1 55 | fi 56 | release_tag="$1" 57 | echo "repo: ${REPO}, release tag: ${release_tag}" 58 | 59 | # Add labels to set for given asset names here: 60 | declare -A assets_labels=( 61 | ["bpftool-libbpf-${release_tag}-sources.tar.gz"]="Source code, including libbpf submodule (tar.gz)" 62 | ) 63 | 64 | # Get release ID 65 | release_id="$(gh api "/repos/${REPO}/releases/tags/${release_tag}" --jq '.id')" 66 | echo " found release ID ${release_id}" 67 | 68 | # For each label to set, get asset ID, prompt user for confirmation, set label 69 | for asset_name in "${!assets_labels[@]}"; do 70 | asset_id="$(gh api "/repos/${REPO}/releases/${release_id}/assets" \ 71 | --jq ".[] | select(.name == \"${asset_name}\").id")" 72 | echo " found asset ID ${asset_id}" 73 | 74 | echo "asset '${asset_name}': add label '${assets_labels[${asset_name}]}'" 75 | answer="" 76 | read -rp 'proceed? [y/N]: ' answer 77 | 78 | case "${answer}" in 79 | y|yes|Y|Yes|YES) 80 | gh api \ 81 | --method PATCH \ 82 | -H 'Accept: application/vnd.github+json' \ 83 | -H 'X-GitHub-Api-Version: 2022-11-28' \ 84 | "/repos/${REPO}/releases/assets/${asset_id}" \ 85 | -f label="${assets_labels[${asset_name}]}" 86 | ;; 87 | *) 88 | echo "cancelled" 89 | ;; 90 | esac 91 | done 92 | -------------------------------------------------------------------------------- /scripts/mailmap-update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | usage () { 6 | echo "USAGE: ./update-mailmap.sh " 7 | exit 1 8 | } 9 | 10 | BPFTOOL_REPO=${1-""} 11 | LINUX_REPO=${2-""} 12 | 13 | if [ -z "${BPFTOOL_REPO}" ] || [ -z "${LINUX_REPO}" ]; then 14 | echo "Error: bpftool or linux repos are not specified" 15 | usage 16 | fi 17 | 18 | BPFTOOL_MAILMAP="${BPFTOOL_REPO}/.mailmap" 19 | LINUX_MAILMAP="${LINUX_REPO}/.mailmap" 20 | 21 | tmpfile="$(mktemp)" 22 | cleanup() { 23 | rm -f "${tmpfile}" 24 | } 25 | trap cleanup EXIT 26 | 27 | grep_lines() { 28 | local pattern="$1" 29 | local file="$2" 30 | grep "${pattern}" "${file}" || true 31 | } 32 | 33 | while read -r email; do 34 | grep_lines "${email}$" "${LINUX_MAILMAP}" >> "${tmpfile}" 35 | done < <(git log --format='<%ae>' | sort -u) 36 | 37 | sort -u "${tmpfile}" > "${BPFTOOL_MAILMAP}" 38 | -------------------------------------------------------------------------------- /scripts/sync-kernel-expected-diff.patch: -------------------------------------------------------------------------------- 1 | --- docs/Makefile 2 | +++ docs/Makefile 3 | @@ -1,5 +1,5 @@ 4 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 5 | -include ../../../scripts/Makefile.include 6 | +include ../src/Makefile.include 7 | 8 | INSTALL ?= install 9 | RM ?= rm -f 10 | --- src/.gitignore 11 | +++ src/.gitignore 12 | @@ -1,8 +1,8 @@ 13 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 14 | +*.o 15 | *.d 16 | /bootstrap/ 17 | /bpftool 18 | -bpftool*.8 19 | FEATURE-DUMP.bpftool 20 | feature 21 | libbpf 22 | --- src/Makefile 23 | +++ src/Makefile 24 | @@ -1,13 +1,11 @@ 25 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 26 | -include ../../scripts/Makefile.include 27 | +include Makefile.include 28 | 29 | ifeq ($(srctree),) 30 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) 31 | -srctree := $(patsubst %/,%,$(dir $(srctree))) 32 | -srctree := $(patsubst %/,%,$(dir $(srctree))) 33 | endif 34 | 35 | -BPF_DIR = $(srctree)/tools/lib/bpf 36 | +BPF_DIR = $(srctree)/libbpf/src 37 | 38 | ifneq ($(OUTPUT),) 39 | _OUTPUT := $(OUTPUT) 40 | @@ -37,16 +35,16 @@ 41 | $(QUIET_MKDIR)mkdir -p $@ 42 | 43 | $(LIBBPF): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_OUTPUT) 44 | - $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_OUTPUT) \ 45 | - DESTDIR=$(LIBBPF_DESTDIR:/=) prefix= $(LIBBPF) install_headers 46 | + $(Q)$(MAKE) -C $(BPF_DIR) OBJDIR=$(patsubst %/,%,$(LIBBPF_OUTPUT)) \ 47 | + DESTDIR="" PREFIX=$(LIBBPF_DESTDIR:/=) $(LIBBPF) install_headers 48 | 49 | $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_DIR) 50 | $(call QUIET_INSTALL, $@) 51 | $(Q)install -m 644 -t $(LIBBPF_HDRS_DIR) $< 52 | 53 | $(LIBBPF_BOOTSTRAP): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_BOOTSTRAP_OUTPUT) 54 | - $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_BOOTSTRAP_OUTPUT) \ 55 | - DESTDIR=$(LIBBPF_BOOTSTRAP_DESTDIR:/=) prefix= \ 56 | + $(Q)$(MAKE) -C $(BPF_DIR) OBJDIR=$(patsubst %/,%,$(LIBBPF_BOOTSTRAP_OUTPUT)) \ 57 | + DESTDIR="" PREFIX=$(LIBBPF_BOOTSTRAP_DESTDIR:/=) \ 58 | ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" $@ install_headers 59 | 60 | $(LIBBPF_BOOTSTRAP_INTERNAL_HDRS): $(LIBBPF_BOOTSTRAP_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_BOOTSTRAP_HDRS_DIR) 61 | @@ -75,9 +73,9 @@ 62 | CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ 63 | -I$(or $(OUTPUT),.) \ 64 | -I$(LIBBPF_INCLUDE) \ 65 | - -I$(srctree)/kernel/bpf/ \ 66 | - -I$(srctree)/tools/include \ 67 | - -I$(srctree)/tools/include/uapi 68 | + -I$(srctree)/src/kernel/bpf/ \ 69 | + -I$(srctree)/include \ 70 | + -I$(srctree)/include/uapi 71 | ifneq ($(BPFTOOL_VERSION),) 72 | CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' 73 | endif 74 | @@ -123,11 +121,7 @@ 75 | endif 76 | 77 | ifeq ($(check_feat),1) 78 | -ifeq ($(FEATURES_DUMP),) 79 | -include $(srctree)/tools/build/Makefile.feature 80 | -else 81 | -include $(FEATURES_DUMP) 82 | -endif 83 | +include Makefile.feature 84 | endif 85 | 86 | LIBS = $(LIBBPF) -lelf -lz 87 | @@ -225,7 +219,7 @@ 88 | $(OUTPUT)%.bpf.o: skeleton/%.bpf.c $(OUTPUT)vmlinux.h $(LIBBPF_BOOTSTRAP) 89 | $(QUIET_CLANG)$(CLANG) \ 90 | -I$(or $(OUTPUT),.) \ 91 | - -I$(srctree)/tools/include/uapi/ \ 92 | + -I$(srctree)/include/uapi/ \ 93 | -I$(LIBBPF_BOOTSTRAP_INCLUDE) \ 94 | -g -O2 -Wall -fno-stack-protector \ 95 | --target=bpf -c $< -o $@ 96 | @@ -243,7 +237,7 @@ 97 | 98 | CFLAGS += $(if $(BUILD_BPF_SKELS),,-DBPFTOOL_WITHOUT_SKELETONS) 99 | 100 | -$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c 101 | +$(OUTPUT)disasm.o: $(srctree)/src/kernel/bpf/disasm.c 102 | $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD $< -o $@ 103 | 104 | $(BPFTOOL_BOOTSTRAP): $(BOOTSTRAP_OBJS) $(LIBBPF_BOOTSTRAP) 105 | @@ -262,7 +256,7 @@ 106 | $(call QUIET_CLEAN, feature-detect) 107 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null 108 | 109 | -clean: $(LIBBPF)-clean $(LIBBPF_BOOTSTRAP)-clean feature-detect-clean 110 | +clean: $(LIBBPF)-clean $(LIBBPF_BOOTSTRAP)-clean 111 | $(call QUIET_CLEAN, bpftool) 112 | $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d 113 | $(Q)$(RM) -- $(OUTPUT)*.skel.h $(OUTPUT)vmlinux.h 114 | @@ -278,7 +272,7 @@ 115 | 116 | install: install-bin 117 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(bash_compdir) 118 | - $(Q)$(INSTALL) -m 0644 bash-completion/bpftool $(DESTDIR)$(bash_compdir) 119 | + $(Q)$(INSTALL) -m 0644 $(srctree)/bash-completion/bpftool $(DESTDIR)$(bash_compdir) 120 | 121 | uninstall: 122 | $(call QUIET_UNINST, bpftool) 123 | @@ -286,16 +280,16 @@ 124 | $(Q)$(RM) -- $(DESTDIR)$(bash_compdir)/bpftool 125 | 126 | doc: 127 | - $(call descend,Documentation) 128 | + $(call descend,$(srctree)/docs) 129 | 130 | doc-clean: 131 | - $(call descend,Documentation,clean) 132 | + $(call descend,$(srctree)/docs,clean) 133 | 134 | doc-install: 135 | - $(call descend,Documentation,install) 136 | + $(call descend,$(srctree)/docs,install) 137 | 138 | doc-uninstall: 139 | - $(call descend,Documentation,uninstall) 140 | + $(call descend,$(srctree)/docs,uninstall) 141 | 142 | FORCE: 143 | 144 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | *.o 3 | *.d 4 | /bootstrap/ 5 | /bpftool 6 | FEATURE-DUMP.bpftool 7 | feature 8 | libbpf 9 | /*.skel.h 10 | /vmlinux.h 11 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | include Makefile.include 3 | 4 | ifeq ($(srctree),) 5 | srctree := $(patsubst %/,%,$(dir $(CURDIR))) 6 | endif 7 | 8 | BPF_DIR = $(srctree)/libbpf/src 9 | 10 | ifneq ($(OUTPUT),) 11 | _OUTPUT := $(OUTPUT) 12 | else 13 | _OUTPUT := $(CURDIR)/ 14 | endif 15 | BOOTSTRAP_OUTPUT := $(_OUTPUT)bootstrap/ 16 | 17 | LIBBPF_OUTPUT := $(_OUTPUT)libbpf/ 18 | LIBBPF_DESTDIR := $(LIBBPF_OUTPUT) 19 | LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)include 20 | LIBBPF_HDRS_DIR := $(LIBBPF_INCLUDE)/bpf 21 | LIBBPF := $(LIBBPF_OUTPUT)libbpf.a 22 | 23 | LIBBPF_BOOTSTRAP_OUTPUT := $(BOOTSTRAP_OUTPUT)libbpf/ 24 | LIBBPF_BOOTSTRAP_DESTDIR := $(LIBBPF_BOOTSTRAP_OUTPUT) 25 | LIBBPF_BOOTSTRAP_INCLUDE := $(LIBBPF_BOOTSTRAP_DESTDIR)include 26 | LIBBPF_BOOTSTRAP_HDRS_DIR := $(LIBBPF_BOOTSTRAP_INCLUDE)/bpf 27 | LIBBPF_BOOTSTRAP := $(LIBBPF_BOOTSTRAP_OUTPUT)libbpf.a 28 | 29 | # We need to copy hashmap.h, nlattr.h, relo_core.h and libbpf_internal.h 30 | # which are not otherwise exported by libbpf, but still required by bpftool. 31 | LIBBPF_INTERNAL_HDRS := $(addprefix $(LIBBPF_HDRS_DIR)/,hashmap.h nlattr.h relo_core.h libbpf_internal.h) 32 | LIBBPF_BOOTSTRAP_INTERNAL_HDRS := $(addprefix $(LIBBPF_BOOTSTRAP_HDRS_DIR)/,hashmap.h relo_core.h libbpf_internal.h) 33 | 34 | $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) $(LIBBPF_BOOTSTRAP_OUTPUT) $(LIBBPF_HDRS_DIR) $(LIBBPF_BOOTSTRAP_HDRS_DIR): 35 | $(QUIET_MKDIR)mkdir -p $@ 36 | 37 | $(LIBBPF): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_OUTPUT) 38 | $(Q)$(MAKE) -C $(BPF_DIR) OBJDIR=$(patsubst %/,%,$(LIBBPF_OUTPUT)) \ 39 | DESTDIR="" PREFIX=$(LIBBPF_DESTDIR:/=) $(LIBBPF) install_headers 40 | 41 | $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_DIR) 42 | $(call QUIET_INSTALL, $@) 43 | $(Q)install -m 644 -t $(LIBBPF_HDRS_DIR) $< 44 | 45 | $(LIBBPF_BOOTSTRAP): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_BOOTSTRAP_OUTPUT) 46 | $(Q)$(MAKE) -C $(BPF_DIR) OBJDIR=$(patsubst %/,%,$(LIBBPF_BOOTSTRAP_OUTPUT)) \ 47 | DESTDIR="" PREFIX=$(LIBBPF_BOOTSTRAP_DESTDIR:/=) \ 48 | ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" $@ install_headers 49 | 50 | $(LIBBPF_BOOTSTRAP_INTERNAL_HDRS): $(LIBBPF_BOOTSTRAP_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_BOOTSTRAP_HDRS_DIR) 51 | $(call QUIET_INSTALL, $@) 52 | $(Q)install -m 644 -t $(LIBBPF_BOOTSTRAP_HDRS_DIR) $< 53 | 54 | $(LIBBPF)-clean: FORCE | $(LIBBPF_OUTPUT) 55 | $(call QUIET_CLEAN, libbpf) 56 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_OUTPUT) clean >/dev/null 57 | 58 | $(LIBBPF_BOOTSTRAP)-clean: FORCE | $(LIBBPF_BOOTSTRAP_OUTPUT) 59 | $(call QUIET_CLEAN, libbpf-bootstrap) 60 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_BOOTSTRAP_OUTPUT) clean >/dev/null 61 | 62 | prefix ?= /usr/local 63 | bash_compdir ?= /usr/share/bash-completion/completions 64 | 65 | CFLAGS += -O2 66 | CFLAGS += -W 67 | CFLAGS += -Wall 68 | CFLAGS += -Wextra 69 | CFLAGS += -Wformat-signedness 70 | CFLAGS += -Wno-unused-parameter 71 | CFLAGS += -Wno-missing-field-initializers 72 | CFLAGS += $(filter-out -Wswitch-enum -Wnested-externs,$(EXTRA_WARNINGS)) 73 | CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ 74 | -I$(or $(OUTPUT),.) \ 75 | -I$(LIBBPF_INCLUDE) \ 76 | -I$(srctree)/src/kernel/bpf/ \ 77 | -I$(srctree)/include \ 78 | -I$(srctree)/include/uapi 79 | ifneq ($(BPFTOOL_VERSION),) 80 | CFLAGS += -DBPFTOOL_VERSION='"$(BPFTOOL_VERSION)"' 81 | endif 82 | ifneq ($(EXTRA_CFLAGS),) 83 | CFLAGS += $(EXTRA_CFLAGS) 84 | endif 85 | ifneq ($(EXTRA_LDFLAGS),) 86 | LDFLAGS += $(EXTRA_LDFLAGS) 87 | endif 88 | 89 | HOST_CFLAGS := $(subst -I$(LIBBPF_INCLUDE),-I$(LIBBPF_BOOTSTRAP_INCLUDE),\ 90 | $(subst $(CLANG_CROSS_FLAGS),,$(CFLAGS))) 91 | HOST_LDFLAGS := $(LDFLAGS) 92 | 93 | INSTALL ?= install 94 | RM ?= rm -f 95 | 96 | FEATURE_USER = .bpftool 97 | 98 | FEATURE_TESTS := clang-bpf-co-re 99 | FEATURE_TESTS += llvm 100 | FEATURE_TESTS += libcap 101 | FEATURE_TESTS += libbfd 102 | FEATURE_TESTS += libbfd-liberty 103 | FEATURE_TESTS += libbfd-liberty-z 104 | FEATURE_TESTS += disassembler-four-args 105 | FEATURE_TESTS += disassembler-init-styled 106 | FEATURE_TESTS += libelf-zstd 107 | 108 | FEATURE_DISPLAY := clang-bpf-co-re 109 | FEATURE_DISPLAY += llvm 110 | FEATURE_DISPLAY += libcap 111 | FEATURE_DISPLAY += libbfd 112 | FEATURE_DISPLAY += libbfd-liberty 113 | FEATURE_DISPLAY += libbfd-liberty-z 114 | 115 | check_feat := 1 116 | NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall 117 | ifdef MAKECMDGOALS 118 | ifeq ($(filter-out $(NON_CHECK_FEAT_TARGETS),$(MAKECMDGOALS)),) 119 | check_feat := 0 120 | endif 121 | endif 122 | 123 | ifeq ($(check_feat),1) 124 | include Makefile.feature 125 | endif 126 | 127 | LIBS = $(LIBBPF) -lelf -lz 128 | LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz 129 | 130 | ifeq ($(feature-libelf-zstd),1) 131 | LIBS += -lzstd 132 | LIBS_BOOTSTRAP += -lzstd 133 | endif 134 | 135 | ifeq ($(feature-libcap), 1) 136 | CFLAGS += -DUSE_LIBCAP 137 | LIBS += -lcap 138 | endif 139 | 140 | include $(wildcard $(OUTPUT)*.d) 141 | 142 | all: $(OUTPUT)bpftool 143 | 144 | SRCS := $(wildcard *.c) 145 | 146 | ifeq ($(feature-llvm),1) 147 | # If LLVM is available, use it for JIT disassembly 148 | CFLAGS += -DHAVE_LLVM_SUPPORT 149 | LLVM_CONFIG_LIB_COMPONENTS := mcdisassembler all-targets 150 | # llvm-config always adds -D_GNU_SOURCE, however, it may already be in CFLAGS 151 | # (e.g. when bpftool build is called from selftests build as selftests 152 | # Makefile includes lib.mk which sets -D_GNU_SOURCE) which would cause 153 | # compilation error due to redefinition. Let's filter it out here. 154 | CFLAGS += $(filter-out -D_GNU_SOURCE,$(shell $(LLVM_CONFIG) --cflags)) 155 | LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS)) 156 | ifeq ($(shell $(LLVM_CONFIG) --shared-mode),static) 157 | LIBS += $(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS)) 158 | LIBS += -lstdc++ 159 | endif 160 | LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags) 161 | else 162 | # Fall back on libbfd 163 | ifeq ($(feature-libbfd),1) 164 | LIBS += -lbfd -ldl -lopcodes 165 | else ifeq ($(feature-libbfd-liberty),1) 166 | LIBS += -lbfd -ldl -lopcodes -liberty 167 | else ifeq ($(feature-libbfd-liberty-z),1) 168 | LIBS += -lbfd -ldl -lopcodes -liberty -lz 169 | endif 170 | 171 | # If one of the above feature combinations is set, we support libbfd 172 | ifneq ($(filter -lbfd,$(LIBS)),) 173 | CFLAGS += -DHAVE_LIBBFD_SUPPORT 174 | 175 | # Libbfd interface changed over time, figure out what we need 176 | ifeq ($(feature-disassembler-four-args), 1) 177 | CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE 178 | endif 179 | ifeq ($(feature-disassembler-init-styled), 1) 180 | CFLAGS += -DDISASM_INIT_STYLED 181 | endif 182 | endif 183 | endif 184 | ifeq ($(filter -DHAVE_LLVM_SUPPORT -DHAVE_LIBBFD_SUPPORT,$(CFLAGS)),) 185 | # No support for JIT disassembly 186 | SRCS := $(filter-out jit_disasm.c,$(SRCS)) 187 | endif 188 | 189 | BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool 190 | 191 | BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o) 192 | $(BOOTSTRAP_OBJS): $(LIBBPF_BOOTSTRAP) 193 | 194 | OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o 195 | $(OBJS): $(LIBBPF) $(LIBBPF_INTERNAL_HDRS) 196 | 197 | VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \ 198 | $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \ 199 | ../../../vmlinux \ 200 | /sys/kernel/btf/vmlinux \ 201 | /boot/vmlinux-$(shell uname -r) 202 | VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) 203 | 204 | bootstrap: $(BPFTOOL_BOOTSTRAP) 205 | 206 | ifneq ($(VMLINUX_BTF)$(VMLINUX_H),) 207 | ifeq ($(feature-clang-bpf-co-re),1) 208 | 209 | BUILD_BPF_SKELS := 1 210 | 211 | ifeq ($(VMLINUX_H),) 212 | $(OUTPUT)vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL_BOOTSTRAP) 213 | $(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) btf dump file $< format c > $@ 214 | else 215 | $(OUTPUT)vmlinux.h: $(VMLINUX_H) 216 | $(Q)cp "$(VMLINUX_H)" $@ 217 | endif 218 | 219 | $(OUTPUT)%.bpf.o: skeleton/%.bpf.c $(OUTPUT)vmlinux.h $(LIBBPF_BOOTSTRAP) 220 | $(QUIET_CLANG)$(CLANG) \ 221 | -I$(or $(OUTPUT),.) \ 222 | -I$(srctree)/include/uapi/ \ 223 | -I$(LIBBPF_BOOTSTRAP_INCLUDE) \ 224 | -g -O2 -Wall -fno-stack-protector \ 225 | --target=bpf -c $< -o $@ 226 | $(Q)$(LLVM_STRIP) -g $@ 227 | 228 | $(OUTPUT)%.skel.h: $(OUTPUT)%.bpf.o $(BPFTOOL_BOOTSTRAP) 229 | $(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) gen skeleton $< > $@ 230 | 231 | $(OUTPUT)prog.o: $(OUTPUT)profiler.skel.h 232 | 233 | $(OUTPUT)pids.o: $(OUTPUT)pid_iter.skel.h 234 | 235 | endif 236 | endif 237 | 238 | CFLAGS += $(if $(BUILD_BPF_SKELS),,-DBPFTOOL_WITHOUT_SKELETONS) 239 | 240 | $(OUTPUT)disasm.o: $(srctree)/src/kernel/bpf/disasm.c 241 | $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD $< -o $@ 242 | 243 | $(BPFTOOL_BOOTSTRAP): $(BOOTSTRAP_OBJS) $(LIBBPF_BOOTSTRAP) 244 | $(QUIET_LINK)$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(BOOTSTRAP_OBJS) $(LIBS_BOOTSTRAP) -o $@ 245 | 246 | $(OUTPUT)bpftool: $(OBJS) $(LIBBPF) 247 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ 248 | 249 | $(BOOTSTRAP_OUTPUT)%.o: %.c $(LIBBPF_BOOTSTRAP_INTERNAL_HDRS) | $(BOOTSTRAP_OUTPUT) 250 | $(QUIET_CC)$(HOSTCC) $(HOST_CFLAGS) -c -MMD $< -o $@ 251 | 252 | $(OUTPUT)%.o: %.c 253 | $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD $< -o $@ 254 | 255 | feature-detect-clean: 256 | $(call QUIET_CLEAN, feature-detect) 257 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null 258 | 259 | clean: $(LIBBPF)-clean $(LIBBPF_BOOTSTRAP)-clean 260 | $(call QUIET_CLEAN, bpftool) 261 | $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d 262 | $(Q)$(RM) -- $(OUTPUT)*.skel.h $(OUTPUT)vmlinux.h 263 | $(Q)$(RM) -r -- $(LIBBPF_OUTPUT) $(BOOTSTRAP_OUTPUT) 264 | $(call QUIET_CLEAN, core-gen) 265 | $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool 266 | $(Q)$(RM) -r -- $(OUTPUT)feature/ 267 | 268 | install-bin: $(OUTPUT)bpftool 269 | $(call QUIET_INSTALL, bpftool) 270 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(prefix)/sbin 271 | $(Q)$(INSTALL) $(OUTPUT)bpftool $(DESTDIR)$(prefix)/sbin/bpftool 272 | 273 | install: install-bin 274 | $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(bash_compdir) 275 | $(Q)$(INSTALL) -m 0644 $(srctree)/bash-completion/bpftool $(DESTDIR)$(bash_compdir) 276 | 277 | uninstall: 278 | $(call QUIET_UNINST, bpftool) 279 | $(Q)$(RM) -- $(DESTDIR)$(prefix)/sbin/bpftool 280 | $(Q)$(RM) -- $(DESTDIR)$(bash_compdir)/bpftool 281 | 282 | doc: 283 | $(call descend,$(srctree)/docs) 284 | 285 | doc-clean: 286 | $(call descend,$(srctree)/docs,clean) 287 | 288 | doc-install: 289 | $(call descend,$(srctree)/docs,install) 290 | 291 | doc-uninstall: 292 | $(call descend,$(srctree)/docs,uninstall) 293 | 294 | FORCE: 295 | 296 | .SECONDARY: 297 | .PHONY: all FORCE bootstrap clean install-bin install uninstall 298 | .PHONY: doc doc-clean doc-install doc-uninstall 299 | .DEFAULT_GOAL := all 300 | 301 | # Delete partially updated (corrupted) files on error 302 | .DELETE_ON_ERROR: 303 | -------------------------------------------------------------------------------- /src/Makefile.feature: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | pound := \# 4 | 5 | CFLAGS_BACKUP := $(CFLAGS) 6 | CFLAGS := $(EXTRA_CFLAGS) 7 | CFLAGS += -Wno-unused-command-line-argument 8 | 9 | ifeq ($(V),1) 10 | LOG=$(warning $(1)) 11 | LOG_RES = (echo $(1) && >&2 echo result: $(1)) 12 | define detect 13 | $(warning $(1) && $(call LOG_RES,1) || $(call LOG_RES,0)) 14 | $(shell $(1) && $(call LOG_RES,1) || $(call LOG_RES,0)) 15 | endef 16 | else 17 | LOG= 18 | LOG_RES = (echo $(1)) 19 | define detect 20 | $(shell $(1) 2>&1 && $(call LOG_RES,1) || $(call LOG_RES,0)) 21 | endef 22 | QUIET_STDERR := 2>/dev/null 23 | endif 24 | 25 | ### feature-clang-bpf-co-re 26 | 27 | CLANG_BPF_CO_RE_PROBE_CMD = \ 28 | printf '%s\n' 'struct s { int i; } __attribute__((preserve_access_index)); struct s foo = {};' | \ 29 | $(CLANG) -g -target bpf -S -o - -x c - $(QUIET_STDERR) | grep -q BTF_KIND_VAR 30 | 31 | ifneq ($(findstring clang-bpf-co-re,$(FEATURE_TESTS)),) 32 | $(call LOG,Probing: feature-clang-bpf-co-re) 33 | feature-clang-bpf-co-re := \ 34 | $(findstring 1,$(call detect,$(CLANG_BPF_CO_RE_PROBE_CMD))) 35 | endif # clang-bpf-co-re 36 | 37 | ### feature-libbfd 38 | 39 | ifneq ($(findstring libbfd,$(FEATURE_TESTS)),) 40 | LIBBFD_PROBE := '$(pound)include \n' 41 | LIBBFD_PROBE += 'int main(void) {' 42 | LIBBFD_PROBE += ' bfd_demangle(0, 0, 0);' 43 | LIBBFD_PROBE += ' return 0;' 44 | LIBBFD_PROBE += '}' 45 | LIBBFD_PROBE_CMD = printf '%b\n' $(LIBBFD_PROBE) | \ 46 | $(CC) $(CFLAGS) -Wall -Werror -x c -DPACKAGE='"bpftool"' - $(1) -o /dev/null >/dev/null 47 | 48 | define libbfd_build 49 | $(call detect,$(LIBBFD_PROBE_CMD)) 50 | endef 51 | 52 | $(call LOG,Probing: feature-libbfd) 53 | feature-libbfd := \ 54 | $(findstring 1,$(call libbfd_build,-lbfd -ldl)) 55 | ifneq ($(feature-libbfd),1) 56 | $(call LOG,Probing: feature-libbfd-liberty) 57 | feature-libbfd-liberty := \ 58 | $(findstring 1,$(call libbfd_build,-lbfd -ldl -liberty)) 59 | ifneq ($(feature-libbfd-liberty),1) 60 | $(call LOG,Probing: feature-libbfd-liberty-z) 61 | feature-libbfd-liberty-z := \ 62 | $(findstring 1,$(call libbfd_build,-lbfd -ldl -liberty -lz)) 63 | endif 64 | endif 65 | HAS_LIBBFD := $(findstring 1, \ 66 | $(feature-libbfd)$(feature-libbfd-liberty)$(feature-libbfd-liberty-z)) 67 | endif # libbfd 68 | 69 | ### feature-disassembler-four-args 70 | 71 | ifneq ($(findstring disassembler-four-args,$(FEATURE_TESTS)),) 72 | DISASSEMBLER_PROBE := '$(pound)include \n' 73 | DISASSEMBLER_PROBE += 'int main(void) {' 74 | DISASSEMBLER_PROBE += ' disassembler((enum bfd_architecture)0, 0, 0, NULL);' 75 | DISASSEMBLER_PROBE += ' return 0;' 76 | DISASSEMBLER_PROBE += '}' 77 | 78 | DISASSEMBLER_PROBE_CMD = printf '%b\n' $(1) | \ 79 | $(CC) $(CFLAGS) -Wall -Werror -x c -DPACKAGE='"bpftool"' - -lbfd -lopcodes -S -o - >/dev/null 80 | define disassembler_build 81 | $(call detect,$(DISASSEMBLER_PROBE_CMD)) 82 | endef 83 | 84 | $(call LOG,Probing: feature-disassembler-four-args) 85 | feature-disassembler-four-args := \ 86 | $(findstring 1, $(call disassembler_build,$(DISASSEMBLER_PROBE))) 87 | endif # disassembler-four-args 88 | 89 | ### feature-disassembler-init-styled 90 | 91 | ifneq ($(findstring disassembler-init-styled,$(FEATURE_TESTS)),) 92 | DISASSEMBLER_STYLED_PROBE := '$(pound)include \n' 93 | DISASSEMBLER_STYLED_PROBE += 'int main(void) {' 94 | DISASSEMBLER_STYLED_PROBE += ' init_disassemble_info(NULL, 0, NULL, NULL);' 95 | DISASSEMBLER_STYLED_PROBE += ' return 0;' 96 | DISASSEMBLER_STYLED_PROBE += '}' 97 | 98 | $(call LOG,Probing: feature-disassembler-styled) 99 | feature-disassembler-init-styled := \ 100 | $(findstring 1, $(call disassembler_build,$(DISASSEMBLER_STYLED_PROBE))) 101 | endif # disassembler-init-styled 102 | 103 | ### feature-libcap 104 | 105 | ifneq ($(findstring libcap,$(FEATURE_TESTS)),) 106 | LIBCAP_PROBE := '$(pound)include \n' 107 | LIBCAP_PROBE += 'int main(void) {' 108 | LIBCAP_PROBE += ' cap_free(0);' 109 | LIBCAP_PROBE += ' return 0;' 110 | LIBCAP_PROBE += '}' 111 | LIBCAP_PROBE_CMD = printf '%b\n' $(LIBCAP_PROBE) | \ 112 | $(CC) $(CFLAGS) -Wall -Werror -x c - -lcap -S -o - >/dev/null 113 | 114 | define libcap_build 115 | $(call detect,$(LIBCAP_PROBE_CMD)) 116 | endef 117 | 118 | $(call LOG,Probing: feature-libcap) 119 | feature-libcap := $(findstring 1, $(call libcap_build)) 120 | endif # libcap 121 | 122 | ### feature-llvm 123 | 124 | ifneq ($(findstring llvm,$(FEATURE_TESTS)),) 125 | LLVM_PROBE := '$(pound)include \n' 126 | LLVM_PROBE += '$(pound)include \n' 127 | LLVM_PROBE += 'int main(void) {' 128 | LLVM_PROBE += ' char *triple = LLVMNormalizeTargetTriple("");' 129 | LLVM_PROBE += ' LLVMDisposeMessage(triple);' 130 | LLVM_PROBE += ' return 0;' 131 | LLVM_PROBE += '}' 132 | 133 | # We need some adjustments for the flags. 134 | # - $(CFLAGS) was set to parent $(EXTRA_CFLAGS) at the beginning of this file. 135 | # - $(EXTRA_LDFLAGS) from parent Makefile should be kept as well. 136 | # - Libraries to use depend on whether we have a static or shared version of 137 | # LLVM, pass the llvm-config flag and adjust the list of libraries 138 | # accordingly. 139 | FEATURE_LLVM_CFLAGS := $(CFLAGS) $(shell $(LLVM_CONFIG) --cflags 2>/dev/null) 140 | FEATURE_LLVM_LIBS := $(shell $(LLVM_CONFIG) --libs target 2>/dev/null) 141 | ifeq ($(shell $(LLVM_CONFIG) --shared-mode 2>/dev/null),static) 142 | FEATURE_LLVM_LIBS += $(shell $(LLVM_CONFIG) --system-libs target 2>/dev/null) 143 | FEATURE_LLVM_LIBS += -lstdc++ 144 | endif 145 | FEATURE_LDFLAGS := $(EXTRA_LDFLAGS) $(shell $(LLVM_CONFIG) --ldflags 2>/dev/null) 146 | 147 | LLVM_PROBE_CMD = printf '%b\n' $(LLVM_PROBE) | \ 148 | $(CC) $(FEATURE_LLVM_CFLAGS) $(FEATURE_LDFLAGS) \ 149 | -Wall -Werror -x c - $(FEATURE_LLVM_LIBS) \ 150 | -o /dev/null >/dev/null 151 | 152 | define llvm_build 153 | $(call detect,$(LLVM_PROBE_CMD)) 154 | endef 155 | 156 | $(call LOG,Probing: feature-llvm) 157 | feature-llvm := $(findstring 1, $(call llvm_build)) 158 | endif # llvm 159 | 160 | ### Print detection results 161 | 162 | define print_status 163 | ifeq ($(1), 1) 164 | MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(2)) 165 | else 166 | MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(2)) 167 | endif 168 | endef 169 | feature_print_status = $(eval $(print_status)) $(info $(MSG)) 170 | 171 | $(call feature_print_status,$(HAS_LIBBFD),libbfd) 172 | 173 | $(foreach feature,$(filter-out libbfd%,$(FEATURE_DISPLAY)), \ 174 | $(call feature_print_status,$(feature-$(feature)),$(feature))) 175 | 176 | CFLAGS := $(CFLAGS_BACKUP) 177 | undefine LOG LOG_RES 178 | -------------------------------------------------------------------------------- /src/Makefile.include: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | 3 | ifneq ($(OUTPUT),) 4 | $(if $(shell [ -d "$(OUTPUT)" -a -x "$(OUTPUT)" ] && echo 1),, \ 5 | $(error output directory "$(OUTPUT)" does not exist)) 6 | endif 7 | 8 | LLVM_VERSION ?= 9 | CLANG ?= clang$(LLVM_VERSION) 10 | LLVM_CONFIG ?= llvm-config$(LLVM_VERSION) 11 | LLVM_STRIP ?= llvm-strip$(LLVM_VERSION) 12 | 13 | ifneq ($(LLVM),) 14 | $(if $(findstring default,$(origin AR)),$(eval AR := llvm-ar$(LLVM_VERSION))) 15 | $(if $(findstring default,$(origin CC)),$(eval CC := clang$(LLVM_VERSION))) 16 | $(if $(findstring default,$(origin LD)),$(eval LD := ld.lld$(LLVM_VERSION))) 17 | HOSTAR ?= llvm-ar 18 | HOSTCC ?= clang 19 | HOSTLD ?= ld.lld 20 | else 21 | $(if $(findstring default,$(origin AR)),$(eval AR = $(CROSS_COMPILE)$(AR))) 22 | $(if $(findstring default,$(origin CC)),$(eval CC = $(CROSS_COMPILE)$(CC))) 23 | $(if $(findstring default,$(origin LD)),$(eval LD = $(CROSS_COMPILE)$(LD))) 24 | HOSTAR ?= ar 25 | HOSTCC ?= gcc 26 | HOSTLD ?= ld 27 | endif 28 | 29 | EXTRA_WARNINGS := \ 30 | -Wbad-function-cast \ 31 | -Wdeclaration-after-statement \ 32 | -Wformat-security \ 33 | -Wformat-y2k \ 34 | -Winit-self \ 35 | -Wmissing-declarations \ 36 | -Wmissing-prototypes \ 37 | -Wold-style-definition \ 38 | -Wpacked \ 39 | -Wredundant-decls \ 40 | -Wshadow \ 41 | -Wstrict-prototypes \ 42 | -Wswitch-default \ 43 | -Wundef \ 44 | -Wwrite-strings \ 45 | 46 | ifeq ($(V),1) 47 | Q = 48 | else 49 | Q = @ 50 | endif 51 | 52 | define descend 53 | mkdir -p $(OUTPUT)$(1) && \ 54 | $(MAKE) --no-print-directory -C $(1) $(2) 55 | endef 56 | 57 | ifeq ($(findstring s,$(firstword -$(MAKEFLAGS))),) 58 | ifneq ($(V),1) 59 | 60 | define def_quiet_msg 61 | $(eval QUIET_$(1) = @printf ' %-9s%s\n' $(1) $$@;) 62 | endef 63 | $(foreach action,CC CLANG LINK MKDIR GEN,$(call def_quiet_msg,$(action))) 64 | 65 | define def_quiet_msg_subdir 66 | $(eval QUIET_$(1) = @printf ' %-9s%s\n' $(1) $$1;) 67 | endef 68 | $(foreach action,CLEAN INSTALL UNINST,$(call def_quiet_msg_subdir,$(action))) 69 | 70 | define descend 71 | @printf ' DESCEND %s\n' $(1); mkdir -p $(OUTPUT)$(1) && \ 72 | $(MAKE) --no-print-directory -C $(1) $(2) 73 | endef 74 | 75 | endif 76 | endif 77 | -------------------------------------------------------------------------------- /src/cfg.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (C) 2018 Netronome Systems, Inc. */ 3 | 4 | #ifndef __BPF_TOOL_CFG_H 5 | #define __BPF_TOOL_CFG_H 6 | 7 | #include "xlated_dumper.h" 8 | 9 | void dump_xlated_cfg(struct dump_data *dd, void *buf, unsigned int len, 10 | bool opcodes, bool linum); 11 | 12 | #endif /* __BPF_TOOL_CFG_H */ 13 | -------------------------------------------------------------------------------- /src/iter.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | // Copyright (C) 2020 Facebook 3 | 4 | #ifndef _GNU_SOURCE 5 | #define _GNU_SOURCE 6 | #endif 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "main.h" 13 | 14 | static int do_pin(int argc, char **argv) 15 | { 16 | DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, iter_opts); 17 | union bpf_iter_link_info linfo; 18 | const char *objfile, *path; 19 | struct bpf_program *prog; 20 | struct bpf_object *obj; 21 | struct bpf_link *link; 22 | int err = -1, map_fd = -1; 23 | 24 | if (!REQ_ARGS(2)) 25 | usage(); 26 | 27 | objfile = GET_ARG(); 28 | path = GET_ARG(); 29 | 30 | /* optional arguments */ 31 | if (argc) { 32 | if (is_prefix(*argv, "map")) { 33 | NEXT_ARG(); 34 | 35 | if (!REQ_ARGS(2)) { 36 | p_err("incorrect map spec"); 37 | return -1; 38 | } 39 | 40 | map_fd = map_parse_fd(&argc, &argv); 41 | if (map_fd < 0) 42 | return -1; 43 | 44 | memset(&linfo, 0, sizeof(linfo)); 45 | linfo.map.map_fd = map_fd; 46 | iter_opts.link_info = &linfo; 47 | iter_opts.link_info_len = sizeof(linfo); 48 | } 49 | } 50 | 51 | obj = bpf_object__open(objfile); 52 | if (!obj) { 53 | err = -errno; 54 | p_err("can't open objfile %s", objfile); 55 | goto close_map_fd; 56 | } 57 | 58 | err = bpf_object__load(obj); 59 | if (err) { 60 | p_err("can't load objfile %s", objfile); 61 | goto close_obj; 62 | } 63 | 64 | prog = bpf_object__next_program(obj, NULL); 65 | if (!prog) { 66 | err = -errno; 67 | p_err("can't find bpf program in objfile %s", objfile); 68 | goto close_obj; 69 | } 70 | 71 | link = bpf_program__attach_iter(prog, &iter_opts); 72 | if (!link) { 73 | err = -errno; 74 | p_err("attach_iter failed for program %s", 75 | bpf_program__name(prog)); 76 | goto close_obj; 77 | } 78 | 79 | err = mount_bpffs_for_file(path); 80 | if (err) 81 | goto close_link; 82 | 83 | err = bpf_link__pin(link, path); 84 | if (err) { 85 | p_err("pin_iter failed for program %s to path %s", 86 | bpf_program__name(prog), path); 87 | goto close_link; 88 | } 89 | 90 | close_link: 91 | bpf_link__destroy(link); 92 | close_obj: 93 | bpf_object__close(obj); 94 | close_map_fd: 95 | if (map_fd >= 0) 96 | close(map_fd); 97 | return err; 98 | } 99 | 100 | static int do_help(int argc, char **argv) 101 | { 102 | fprintf(stderr, 103 | "Usage: %1$s %2$s pin OBJ PATH [map MAP]\n" 104 | " %1$s %2$s help\n" 105 | "\n" 106 | " " HELP_SPEC_MAP "\n" 107 | " " HELP_SPEC_OPTIONS " }\n" 108 | "", 109 | bin_name, "iter"); 110 | 111 | return 0; 112 | } 113 | 114 | static const struct cmd cmds[] = { 115 | { "help", do_help }, 116 | { "pin", do_pin }, 117 | { 0 } 118 | }; 119 | 120 | int do_iter(int argc, char **argv) 121 | { 122 | return cmd_select(cmds, argc, argv, do_help); 123 | } 124 | -------------------------------------------------------------------------------- /src/json_writer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * Simple streaming JSON writer 4 | * 5 | * This takes care of the annoying bits of JSON syntax like the commas 6 | * after elements 7 | * 8 | * Authors: Stephen Hemminger 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "json_writer.h" 20 | 21 | struct json_writer { 22 | FILE *out; /* output file */ 23 | unsigned depth; /* nesting */ 24 | bool pretty; /* optional whitepace */ 25 | char sep; /* either nul or comma */ 26 | }; 27 | 28 | /* indentation for pretty print */ 29 | static void jsonw_indent(json_writer_t *self) 30 | { 31 | unsigned i; 32 | for (i = 0; i < self->depth; ++i) 33 | fputs(" ", self->out); 34 | } 35 | 36 | /* end current line and indent if pretty printing */ 37 | static void jsonw_eol(json_writer_t *self) 38 | { 39 | if (!self->pretty) 40 | return; 41 | 42 | putc('\n', self->out); 43 | jsonw_indent(self); 44 | } 45 | 46 | /* If current object is not empty print a comma */ 47 | static void jsonw_eor(json_writer_t *self) 48 | { 49 | if (self->sep != '\0') 50 | putc(self->sep, self->out); 51 | self->sep = ','; 52 | } 53 | 54 | 55 | /* Output JSON encoded string */ 56 | /* Handles C escapes, does not do Unicode */ 57 | static void jsonw_puts(json_writer_t *self, const char *str) 58 | { 59 | putc('"', self->out); 60 | for (; *str; ++str) 61 | switch (*str) { 62 | case '\t': 63 | fputs("\\t", self->out); 64 | break; 65 | case '\n': 66 | fputs("\\n", self->out); 67 | break; 68 | case '\r': 69 | fputs("\\r", self->out); 70 | break; 71 | case '\f': 72 | fputs("\\f", self->out); 73 | break; 74 | case '\b': 75 | fputs("\\b", self->out); 76 | break; 77 | case '\\': 78 | fputs("\\\\", self->out); 79 | break; 80 | case '"': 81 | fputs("\\\"", self->out); 82 | break; 83 | default: 84 | putc(*str, self->out); 85 | } 86 | putc('"', self->out); 87 | } 88 | 89 | /* Create a new JSON stream */ 90 | json_writer_t *jsonw_new(FILE *f) 91 | { 92 | json_writer_t *self = malloc(sizeof(*self)); 93 | if (self) { 94 | self->out = f; 95 | self->depth = 0; 96 | self->pretty = false; 97 | self->sep = '\0'; 98 | } 99 | return self; 100 | } 101 | 102 | /* End output to JSON stream */ 103 | void jsonw_destroy(json_writer_t **self_p) 104 | { 105 | json_writer_t *self = *self_p; 106 | 107 | assert(self->depth == 0); 108 | fputs("\n", self->out); 109 | fflush(self->out); 110 | free(self); 111 | *self_p = NULL; 112 | } 113 | 114 | void jsonw_pretty(json_writer_t *self, bool on) 115 | { 116 | self->pretty = on; 117 | } 118 | 119 | void jsonw_reset(json_writer_t *self) 120 | { 121 | assert(self->depth == 0); 122 | self->sep = '\0'; 123 | } 124 | 125 | /* Basic blocks */ 126 | static void jsonw_begin(json_writer_t *self, int c) 127 | { 128 | jsonw_eor(self); 129 | putc(c, self->out); 130 | ++self->depth; 131 | self->sep = '\0'; 132 | } 133 | 134 | static void jsonw_end(json_writer_t *self, int c) 135 | { 136 | assert(self->depth > 0); 137 | 138 | --self->depth; 139 | if (self->sep != '\0') 140 | jsonw_eol(self); 141 | putc(c, self->out); 142 | self->sep = ','; 143 | } 144 | 145 | 146 | /* Add a JSON property name */ 147 | void jsonw_name(json_writer_t *self, const char *name) 148 | { 149 | jsonw_eor(self); 150 | jsonw_eol(self); 151 | self->sep = '\0'; 152 | jsonw_puts(self, name); 153 | putc(':', self->out); 154 | if (self->pretty) 155 | putc(' ', self->out); 156 | } 157 | 158 | void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) 159 | { 160 | jsonw_eor(self); 161 | putc('"', self->out); 162 | vfprintf(self->out, fmt, ap); 163 | putc('"', self->out); 164 | } 165 | 166 | void jsonw_printf(json_writer_t *self, const char *fmt, ...) 167 | { 168 | va_list ap; 169 | 170 | va_start(ap, fmt); 171 | jsonw_eor(self); 172 | vfprintf(self->out, fmt, ap); 173 | va_end(ap); 174 | } 175 | 176 | /* Collections */ 177 | void jsonw_start_object(json_writer_t *self) 178 | { 179 | jsonw_begin(self, '{'); 180 | } 181 | 182 | void jsonw_end_object(json_writer_t *self) 183 | { 184 | jsonw_end(self, '}'); 185 | } 186 | 187 | void jsonw_start_array(json_writer_t *self) 188 | { 189 | jsonw_begin(self, '['); 190 | } 191 | 192 | void jsonw_end_array(json_writer_t *self) 193 | { 194 | jsonw_end(self, ']'); 195 | } 196 | 197 | /* JSON value types */ 198 | void jsonw_string(json_writer_t *self, const char *value) 199 | { 200 | jsonw_eor(self); 201 | jsonw_puts(self, value); 202 | } 203 | 204 | void jsonw_bool(json_writer_t *self, bool val) 205 | { 206 | jsonw_printf(self, "%s", val ? "true" : "false"); 207 | } 208 | 209 | void jsonw_null(json_writer_t *self) 210 | { 211 | jsonw_printf(self, "null"); 212 | } 213 | 214 | void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) 215 | { 216 | jsonw_printf(self, fmt, num); 217 | } 218 | 219 | #ifdef notused 220 | void jsonw_float(json_writer_t *self, double num) 221 | { 222 | jsonw_printf(self, "%g", num); 223 | } 224 | #endif 225 | 226 | void jsonw_hu(json_writer_t *self, unsigned short num) 227 | { 228 | jsonw_printf(self, "%hu", num); 229 | } 230 | 231 | void jsonw_uint(json_writer_t *self, uint64_t num) 232 | { 233 | jsonw_printf(self, "%"PRIu64, num); 234 | } 235 | 236 | void jsonw_lluint(json_writer_t *self, unsigned long long int num) 237 | { 238 | jsonw_printf(self, "%llu", num); 239 | } 240 | 241 | void jsonw_int(json_writer_t *self, int64_t num) 242 | { 243 | jsonw_printf(self, "%"PRId64, num); 244 | } 245 | 246 | /* Basic name/value objects */ 247 | void jsonw_string_field(json_writer_t *self, const char *prop, const char *val) 248 | { 249 | jsonw_name(self, prop); 250 | jsonw_string(self, val); 251 | } 252 | 253 | void jsonw_bool_field(json_writer_t *self, const char *prop, bool val) 254 | { 255 | jsonw_name(self, prop); 256 | jsonw_bool(self, val); 257 | } 258 | 259 | #ifdef notused 260 | void jsonw_float_field(json_writer_t *self, const char *prop, double val) 261 | { 262 | jsonw_name(self, prop); 263 | jsonw_float(self, val); 264 | } 265 | #endif 266 | 267 | void jsonw_float_field_fmt(json_writer_t *self, 268 | const char *prop, 269 | const char *fmt, 270 | double val) 271 | { 272 | jsonw_name(self, prop); 273 | jsonw_float_fmt(self, fmt, val); 274 | } 275 | 276 | void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num) 277 | { 278 | jsonw_name(self, prop); 279 | jsonw_uint(self, num); 280 | } 281 | 282 | void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num) 283 | { 284 | jsonw_name(self, prop); 285 | jsonw_hu(self, num); 286 | } 287 | 288 | void jsonw_lluint_field(json_writer_t *self, 289 | const char *prop, 290 | unsigned long long int num) 291 | { 292 | jsonw_name(self, prop); 293 | jsonw_lluint(self, num); 294 | } 295 | 296 | void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num) 297 | { 298 | jsonw_name(self, prop); 299 | jsonw_int(self, num); 300 | } 301 | 302 | void jsonw_null_field(json_writer_t *self, const char *prop) 303 | { 304 | jsonw_name(self, prop); 305 | jsonw_null(self); 306 | } 307 | 308 | #ifdef TEST 309 | int main(int argc, char **argv) 310 | { 311 | json_writer_t *wr = jsonw_new(stdout); 312 | 313 | jsonw_start_object(wr); 314 | jsonw_pretty(wr, true); 315 | jsonw_name(wr, "Vyatta"); 316 | jsonw_start_object(wr); 317 | jsonw_string_field(wr, "url", "http://vyatta.com"); 318 | jsonw_uint_field(wr, "downloads", 2000000ul); 319 | jsonw_float_field(wr, "stock", 8.16); 320 | 321 | jsonw_name(wr, "ARGV"); 322 | jsonw_start_array(wr); 323 | while (--argc) 324 | jsonw_string(wr, *++argv); 325 | jsonw_end_array(wr); 326 | 327 | jsonw_name(wr, "empty"); 328 | jsonw_start_array(wr); 329 | jsonw_end_array(wr); 330 | 331 | jsonw_name(wr, "NIL"); 332 | jsonw_start_object(wr); 333 | jsonw_end_object(wr); 334 | 335 | jsonw_null_field(wr, "my_null"); 336 | 337 | jsonw_name(wr, "special chars"); 338 | jsonw_start_array(wr); 339 | jsonw_string_field(wr, "slash", "/"); 340 | jsonw_string_field(wr, "newline", "\n"); 341 | jsonw_string_field(wr, "tab", "\t"); 342 | jsonw_string_field(wr, "ff", "\f"); 343 | jsonw_string_field(wr, "quote", "\""); 344 | jsonw_string_field(wr, "tick", "\'"); 345 | jsonw_string_field(wr, "backslash", "\\"); 346 | jsonw_end_array(wr); 347 | 348 | jsonw_end_object(wr); 349 | 350 | jsonw_end_object(wr); 351 | jsonw_destroy(&wr); 352 | return 0; 353 | } 354 | 355 | #endif 356 | -------------------------------------------------------------------------------- /src/json_writer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* 3 | * Simple streaming JSON writer 4 | * 5 | * This takes care of the annoying bits of JSON syntax like the commas 6 | * after elements 7 | * 8 | * Authors: Stephen Hemminger 9 | */ 10 | 11 | #ifndef _JSON_WRITER_H_ 12 | #define _JSON_WRITER_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | /* Opaque class structure */ 21 | typedef struct json_writer json_writer_t; 22 | 23 | /* Create a new JSON stream */ 24 | json_writer_t *jsonw_new(FILE *f); 25 | /* End output to JSON stream */ 26 | void jsonw_destroy(json_writer_t **self_p); 27 | 28 | /* Cause output to have pretty whitespace */ 29 | void jsonw_pretty(json_writer_t *self, bool on); 30 | 31 | /* Reset separator to create new JSON */ 32 | void jsonw_reset(json_writer_t *self); 33 | 34 | /* Add property name */ 35 | void jsonw_name(json_writer_t *self, const char *name); 36 | 37 | /* Add value */ 38 | void __printf(2, 0) jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, 39 | va_list ap); 40 | void __printf(2, 3) jsonw_printf(json_writer_t *self, const char *fmt, ...); 41 | void jsonw_string(json_writer_t *self, const char *value); 42 | void jsonw_bool(json_writer_t *self, bool value); 43 | void jsonw_float(json_writer_t *self, double number); 44 | void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num); 45 | void jsonw_uint(json_writer_t *self, uint64_t number); 46 | void jsonw_hu(json_writer_t *self, unsigned short number); 47 | void jsonw_int(json_writer_t *self, int64_t number); 48 | void jsonw_null(json_writer_t *self); 49 | void jsonw_lluint(json_writer_t *self, unsigned long long int num); 50 | 51 | /* Useful Combinations of name and value */ 52 | void jsonw_string_field(json_writer_t *self, const char *prop, const char *val); 53 | void jsonw_bool_field(json_writer_t *self, const char *prop, bool value); 54 | void jsonw_float_field(json_writer_t *self, const char *prop, double num); 55 | void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num); 56 | void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num); 57 | void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num); 58 | void jsonw_null_field(json_writer_t *self, const char *prop); 59 | void jsonw_lluint_field(json_writer_t *self, const char *prop, 60 | unsigned long long int num); 61 | void jsonw_float_field_fmt(json_writer_t *self, const char *prop, 62 | const char *fmt, double val); 63 | 64 | /* Collections */ 65 | void jsonw_start_object(json_writer_t *self); 66 | void jsonw_end_object(json_writer_t *self); 67 | 68 | void jsonw_start_array(json_writer_t *self); 69 | void jsonw_end_array(json_writer_t *self); 70 | 71 | /* Override default exception handling */ 72 | typedef void (jsonw_err_handler_fn)(const char *); 73 | 74 | #endif /* _JSON_WRITER_H_ */ 75 | -------------------------------------------------------------------------------- /src/kernel/bpf/disasm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 3 | * Copyright (c) 2016 Facebook 4 | */ 5 | 6 | #ifndef __BPF_DISASM_H__ 7 | #define __BPF_DISASM_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | #ifndef __KERNEL__ 13 | #include 14 | #include 15 | #endif 16 | 17 | extern const char *const bpf_alu_string[16]; 18 | extern const char *const bpf_class_string[8]; 19 | 20 | const char *func_id_name(int id); 21 | 22 | typedef __printf(2, 3) void (*bpf_insn_print_t)(void *private_data, 23 | const char *, ...); 24 | typedef const char *(*bpf_insn_revmap_call_t)(void *private_data, 25 | const struct bpf_insn *insn); 26 | typedef const char *(*bpf_insn_print_imm_t)(void *private_data, 27 | const struct bpf_insn *insn, 28 | __u64 full_imm); 29 | 30 | struct bpf_insn_cbs { 31 | bpf_insn_print_t cb_print; 32 | bpf_insn_revmap_call_t cb_call; 33 | bpf_insn_print_imm_t cb_imm; 34 | void *private_data; 35 | }; 36 | 37 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, 38 | const struct bpf_insn *insn, 39 | bool allow_ptr_leaks); 40 | #endif 41 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 | 4 | #ifndef __BPF_TOOL_H 5 | #define __BPF_TOOL_H 6 | 7 | /* BFD and kernel.h both define GCC_VERSION, differently */ 8 | #undef GCC_VERSION 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include "json_writer.h" 20 | 21 | /* Make sure we do not use kernel-only integer typedefs */ 22 | #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 23 | 24 | static inline __u64 ptr_to_u64(const void *ptr) 25 | { 26 | return (__u64)(unsigned long)ptr; 27 | } 28 | 29 | static inline void *u64_to_ptr(__u64 ptr) 30 | { 31 | return (void *)(unsigned long)ptr; 32 | } 33 | 34 | #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) 35 | #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) 36 | #define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; }) 37 | #define GET_ARG() ({ argc--; *argv++; }) 38 | #define REQ_ARGS(cnt) \ 39 | ({ \ 40 | int _cnt = (cnt); \ 41 | bool _res; \ 42 | \ 43 | if (argc < _cnt) { \ 44 | p_err("'%s' needs at least %d arguments, %d found", \ 45 | argv[-1], _cnt, argc); \ 46 | _res = false; \ 47 | } else { \ 48 | _res = true; \ 49 | } \ 50 | _res; \ 51 | }) 52 | 53 | #define ERR_MAX_LEN 1024 54 | 55 | #define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" 56 | 57 | #define HELP_SPEC_PROGRAM \ 58 | "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG | name PROG_NAME }" 59 | #define HELP_SPEC_OPTIONS \ 60 | "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-d|--debug}" 61 | #define HELP_SPEC_MAP \ 62 | "MAP := { id MAP_ID | pinned FILE | name MAP_NAME }" 63 | #define HELP_SPEC_LINK \ 64 | "LINK := { id LINK_ID | pinned FILE }" 65 | 66 | /* keep in sync with the definition in skeleton/pid_iter.bpf.c */ 67 | enum bpf_obj_type { 68 | BPF_OBJ_UNKNOWN, 69 | BPF_OBJ_PROG, 70 | BPF_OBJ_MAP, 71 | BPF_OBJ_LINK, 72 | BPF_OBJ_BTF, 73 | }; 74 | 75 | extern const char *bin_name; 76 | 77 | extern json_writer_t *json_wtr; 78 | extern bool json_output; 79 | extern bool show_pinned; 80 | extern bool show_pids; 81 | extern bool block_mount; 82 | extern bool verifier_logs; 83 | extern bool relaxed_maps; 84 | extern bool use_loader; 85 | extern struct btf *base_btf; 86 | extern struct hashmap *refs_table; 87 | 88 | void __printf(1, 2) p_err(const char *fmt, ...); 89 | void __printf(1, 2) p_info(const char *fmt, ...); 90 | 91 | bool is_prefix(const char *pfx, const char *str); 92 | int detect_common_prefix(const char *arg, ...); 93 | void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep); 94 | void usage(void) __noreturn; 95 | 96 | void set_max_rlimit(void); 97 | 98 | int mount_tracefs(const char *target); 99 | 100 | struct obj_ref { 101 | int pid; 102 | char comm[16]; 103 | }; 104 | 105 | struct obj_refs { 106 | int ref_cnt; 107 | bool has_bpf_cookie; 108 | struct obj_ref *refs; 109 | __u64 bpf_cookie; 110 | }; 111 | 112 | struct btf; 113 | struct bpf_line_info; 114 | 115 | int build_pinned_obj_table(struct hashmap *table, 116 | enum bpf_obj_type type); 117 | void delete_pinned_obj_table(struct hashmap *table); 118 | __weak int build_obj_refs_table(struct hashmap **table, 119 | enum bpf_obj_type type); 120 | __weak void delete_obj_refs_table(struct hashmap *table); 121 | __weak void emit_obj_refs_json(struct hashmap *table, __u32 id, 122 | json_writer_t *json_wtr); 123 | __weak void emit_obj_refs_plain(struct hashmap *table, __u32 id, 124 | const char *prefix); 125 | void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); 126 | void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode); 127 | 128 | struct cmd { 129 | const char *cmd; 130 | int (*func)(int argc, char **argv); 131 | }; 132 | 133 | int cmd_select(const struct cmd *cmds, int argc, char **argv, 134 | int (*help)(int argc, char **argv)); 135 | 136 | #define MAX_PROG_FULL_NAME 128 137 | void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd, 138 | char *name_buff, size_t buff_len); 139 | 140 | int get_fd_type(int fd); 141 | const char *get_fd_type_name(enum bpf_obj_type type); 142 | char *get_fdinfo(int fd, const char *key); 143 | int open_obj_pinned(const char *path, bool quiet); 144 | int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type); 145 | int mount_bpffs_for_file(const char *file_name); 146 | int create_and_mount_bpffs_dir(const char *dir_name); 147 | int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); 148 | int do_pin_fd(int fd, const char *name); 149 | 150 | /* commands available in bootstrap mode */ 151 | int do_gen(int argc, char **argv); 152 | int do_btf(int argc, char **argv); 153 | 154 | /* non-bootstrap only commands */ 155 | int do_prog(int argc, char **arg) __weak; 156 | int do_map(int argc, char **arg) __weak; 157 | int do_link(int argc, char **arg) __weak; 158 | int do_event_pipe(int argc, char **argv) __weak; 159 | int do_cgroup(int argc, char **arg) __weak; 160 | int do_perf(int argc, char **arg) __weak; 161 | int do_net(int argc, char **arg) __weak; 162 | int do_tracelog(int argc, char **arg) __weak; 163 | int do_feature(int argc, char **argv) __weak; 164 | int do_struct_ops(int argc, char **argv) __weak; 165 | int do_iter(int argc, char **argv) __weak; 166 | 167 | int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); 168 | int prog_parse_fd(int *argc, char ***argv); 169 | int prog_parse_fds(int *argc, char ***argv, int **fds); 170 | int map_parse_fd(int *argc, char ***argv); 171 | int map_parse_fds(int *argc, char ***argv, int **fds); 172 | int map_parse_fd_and_info(int *argc, char ***argv, struct bpf_map_info *info, 173 | __u32 *info_len); 174 | 175 | struct bpf_prog_linfo; 176 | #if defined(HAVE_LLVM_SUPPORT) || defined(HAVE_LIBBFD_SUPPORT) 177 | int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 178 | const char *arch, const char *disassembler_options, 179 | const struct btf *btf, 180 | const struct bpf_prog_linfo *prog_linfo, 181 | __u64 func_ksym, unsigned int func_idx, 182 | bool linum); 183 | int disasm_init(void); 184 | #else 185 | static inline 186 | int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 187 | const char *arch, const char *disassembler_options, 188 | const struct btf *btf, 189 | const struct bpf_prog_linfo *prog_linfo, 190 | __u64 func_ksym, unsigned int func_idx, 191 | bool linum) 192 | { 193 | return 0; 194 | } 195 | static inline int disasm_init(void) 196 | { 197 | p_err("No JIT disassembly support"); 198 | return -1; 199 | } 200 | #endif 201 | void print_data_json(uint8_t *data, size_t len); 202 | void print_hex_data_json(uint8_t *data, size_t len); 203 | 204 | unsigned int get_page_size(void); 205 | unsigned int get_possible_cpus(void); 206 | const char * 207 | ifindex_to_arch(__u32 ifindex, __u64 ns_dev, __u64 ns_ino, const char **opt); 208 | 209 | struct btf_dumper { 210 | const struct btf *btf; 211 | json_writer_t *jw; 212 | bool is_plain_text; 213 | bool prog_id_as_func_ptr; 214 | }; 215 | 216 | /* btf_dumper_type - print data along with type information 217 | * @d: an instance containing context for dumping types 218 | * @type_id: index in btf->types array. this points to the type to be dumped 219 | * @data: pointer the actual data, i.e. the values to be printed 220 | * 221 | * Returns zero on success and negative error code otherwise 222 | */ 223 | int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, 224 | const void *data); 225 | void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id, 226 | char *func_only, int size); 227 | 228 | void btf_dump_linfo_plain(const struct btf *btf, 229 | const struct bpf_line_info *linfo, 230 | const char *prefix, bool linum); 231 | void btf_dump_linfo_json(const struct btf *btf, 232 | const struct bpf_line_info *linfo, bool linum); 233 | void btf_dump_linfo_dotlabel(const struct btf *btf, 234 | const struct bpf_line_info *linfo, bool linum); 235 | 236 | struct nlattr; 237 | struct ifinfomsg; 238 | struct tcmsg; 239 | int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb); 240 | int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind, 241 | const char *devname, int ifindex); 242 | 243 | int print_all_levels(__maybe_unused enum libbpf_print_level level, 244 | const char *format, va_list args); 245 | 246 | size_t hash_fn_for_key_as_id(long key, void *ctx); 247 | bool equal_fn_for_key_as_id(long k1, long k2, void *ctx); 248 | 249 | /* bpf_attach_type_input_str - convert the provided attach type value into a 250 | * textual representation that we accept for input purposes. 251 | * 252 | * This function is similar in nature to libbpf_bpf_attach_type_str, but 253 | * recognizes some attach type names that have been used by the program in the 254 | * past and which do not follow the string inference scheme that libbpf uses. 255 | * These textual representations should only be used for user input. 256 | * 257 | * @t: The attach type 258 | * Returns a pointer to a static string identifying the attach type. NULL is 259 | * returned for unknown bpf_attach_type values. 260 | */ 261 | const char *bpf_attach_type_input_str(enum bpf_attach_type t); 262 | 263 | static inline bool hashmap__empty(struct hashmap *map) 264 | { 265 | return map ? hashmap__size(map) == 0 : true; 266 | } 267 | 268 | int pathname_concat(char *buf, int buf_sz, const char *path, 269 | const char *name); 270 | 271 | /* print netfilter bpf_link info */ 272 | void netfilter_dump_plain(const struct bpf_link_info *info); 273 | void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr); 274 | #endif 275 | -------------------------------------------------------------------------------- /src/map_perf_ring.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | /* Copyright (C) 2018 Netronome Systems, Inc. */ 3 | /* This program is free software; you can redistribute it and/or 4 | * modify it under the terms of version 2 of the GNU General Public 5 | * License as published by the Free Software Foundation. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "main.h" 27 | 28 | #define MMAP_PAGE_CNT 16 29 | 30 | static volatile bool stop; 31 | 32 | struct perf_event_sample { 33 | struct perf_event_header header; 34 | __u64 time; 35 | __u32 size; 36 | unsigned char data[]; 37 | }; 38 | 39 | struct perf_event_lost { 40 | struct perf_event_header header; 41 | __u64 id; 42 | __u64 lost; 43 | }; 44 | 45 | static void int_exit(int signo) 46 | { 47 | fprintf(stderr, "Stopping...\n"); 48 | stop = true; 49 | } 50 | 51 | struct event_pipe_ctx { 52 | bool all_cpus; 53 | int cpu; 54 | int idx; 55 | }; 56 | 57 | static enum bpf_perf_event_ret 58 | print_bpf_output(void *private_data, int cpu, struct perf_event_header *event) 59 | { 60 | struct perf_event_sample *e = container_of(event, 61 | struct perf_event_sample, 62 | header); 63 | struct perf_event_lost *lost = container_of(event, 64 | struct perf_event_lost, 65 | header); 66 | struct event_pipe_ctx *ctx = private_data; 67 | int idx = ctx->all_cpus ? cpu : ctx->idx; 68 | 69 | if (json_output) { 70 | jsonw_start_object(json_wtr); 71 | jsonw_name(json_wtr, "type"); 72 | jsonw_uint(json_wtr, e->header.type); 73 | jsonw_name(json_wtr, "cpu"); 74 | jsonw_uint(json_wtr, cpu); 75 | jsonw_name(json_wtr, "index"); 76 | jsonw_uint(json_wtr, idx); 77 | if (e->header.type == PERF_RECORD_SAMPLE) { 78 | jsonw_name(json_wtr, "timestamp"); 79 | jsonw_uint(json_wtr, e->time); 80 | jsonw_name(json_wtr, "data"); 81 | print_data_json(e->data, e->size); 82 | } else if (e->header.type == PERF_RECORD_LOST) { 83 | jsonw_name(json_wtr, "lost"); 84 | jsonw_start_object(json_wtr); 85 | jsonw_name(json_wtr, "id"); 86 | jsonw_uint(json_wtr, lost->id); 87 | jsonw_name(json_wtr, "count"); 88 | jsonw_uint(json_wtr, lost->lost); 89 | jsonw_end_object(json_wtr); 90 | } 91 | jsonw_end_object(json_wtr); 92 | } else { 93 | if (e->header.type == PERF_RECORD_SAMPLE) { 94 | printf("== @%llu.%09llu CPU: %d index: %d =====\n", 95 | e->time / 1000000000ULL, e->time % 1000000000ULL, 96 | cpu, idx); 97 | fprint_hex(stdout, e->data, e->size, " "); 98 | printf("\n"); 99 | } else if (e->header.type == PERF_RECORD_LOST) { 100 | printf("lost %llu events\n", lost->lost); 101 | } else { 102 | printf("unknown event type=%u size=%u\n", 103 | e->header.type, e->header.size); 104 | } 105 | } 106 | 107 | return LIBBPF_PERF_EVENT_CONT; 108 | } 109 | 110 | int do_event_pipe(int argc, char **argv) 111 | { 112 | struct perf_event_attr perf_attr = { 113 | .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME, 114 | .type = PERF_TYPE_SOFTWARE, 115 | .config = PERF_COUNT_SW_BPF_OUTPUT, 116 | .sample_period = 1, 117 | .wakeup_events = 1, 118 | }; 119 | struct bpf_map_info map_info = {}; 120 | LIBBPF_OPTS(perf_buffer_raw_opts, opts); 121 | struct event_pipe_ctx ctx = { 122 | .all_cpus = true, 123 | .cpu = -1, 124 | .idx = -1, 125 | }; 126 | struct perf_buffer *pb; 127 | __u32 map_info_len; 128 | int err, map_fd; 129 | 130 | map_info_len = sizeof(map_info); 131 | map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len); 132 | if (map_fd < 0) 133 | return -1; 134 | 135 | if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { 136 | p_err("map is not a perf event array"); 137 | goto err_close_map; 138 | } 139 | 140 | while (argc) { 141 | if (argc < 2) { 142 | BAD_ARG(); 143 | goto err_close_map; 144 | } 145 | 146 | if (is_prefix(*argv, "cpu")) { 147 | char *endptr; 148 | 149 | NEXT_ARG(); 150 | ctx.cpu = strtoul(*argv, &endptr, 0); 151 | if (*endptr) { 152 | p_err("can't parse %s as CPU ID", *argv); 153 | goto err_close_map; 154 | } 155 | 156 | NEXT_ARG(); 157 | } else if (is_prefix(*argv, "index")) { 158 | char *endptr; 159 | 160 | NEXT_ARG(); 161 | ctx.idx = strtoul(*argv, &endptr, 0); 162 | if (*endptr) { 163 | p_err("can't parse %s as index", *argv); 164 | goto err_close_map; 165 | } 166 | 167 | NEXT_ARG(); 168 | } else { 169 | BAD_ARG(); 170 | goto err_close_map; 171 | } 172 | 173 | ctx.all_cpus = false; 174 | } 175 | 176 | if (!ctx.all_cpus) { 177 | if (ctx.idx == -1 || ctx.cpu == -1) { 178 | p_err("cpu and index must be specified together"); 179 | goto err_close_map; 180 | } 181 | } else { 182 | ctx.cpu = 0; 183 | ctx.idx = 0; 184 | } 185 | 186 | opts.cpu_cnt = ctx.all_cpus ? 0 : 1; 187 | opts.cpus = &ctx.cpu; 188 | opts.map_keys = &ctx.idx; 189 | pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &perf_attr, 190 | print_bpf_output, &ctx, &opts); 191 | if (!pb) { 192 | p_err("failed to create perf buffer: %s (%d)", 193 | strerror(errno), errno); 194 | goto err_close_map; 195 | } 196 | 197 | signal(SIGINT, int_exit); 198 | signal(SIGHUP, int_exit); 199 | signal(SIGTERM, int_exit); 200 | 201 | if (json_output) 202 | jsonw_start_array(json_wtr); 203 | 204 | while (!stop) { 205 | err = perf_buffer__poll(pb, 200); 206 | if (err < 0 && err != -EINTR) { 207 | p_err("perf buffer polling failed: %s (%d)", 208 | strerror(errno), errno); 209 | goto err_close_pb; 210 | } 211 | } 212 | 213 | if (json_output) 214 | jsonw_end_array(json_wtr); 215 | 216 | perf_buffer__free(pb); 217 | close(map_fd); 218 | 219 | return 0; 220 | 221 | err_close_pb: 222 | perf_buffer__free(pb); 223 | err_close_map: 224 | close(map_fd); 225 | return -1; 226 | } 227 | -------------------------------------------------------------------------------- /src/netlink_dumper.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | // Copyright (C) 2018 Facebook 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "bpf/nlattr.h" 11 | #include "main.h" 12 | #include "netlink_dumper.h" 13 | 14 | static void xdp_dump_prog_id(struct nlattr **tb, int attr, 15 | const char *mode, 16 | bool new_json_object) 17 | { 18 | if (!tb[attr]) 19 | return; 20 | 21 | if (new_json_object) 22 | NET_START_OBJECT 23 | NET_DUMP_STR("mode", " %s", mode); 24 | NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr])) 25 | if (new_json_object) 26 | NET_END_OBJECT 27 | } 28 | 29 | static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex, 30 | const char *name) 31 | { 32 | struct nlattr *tb[IFLA_XDP_MAX + 1]; 33 | unsigned char mode; 34 | 35 | if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0) 36 | return -1; 37 | 38 | if (!tb[IFLA_XDP_ATTACHED]) 39 | return 0; 40 | 41 | mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]); 42 | if (mode == XDP_ATTACHED_NONE) 43 | return 0; 44 | 45 | NET_START_OBJECT; 46 | if (name) 47 | NET_DUMP_STR("devname", "%s", name); 48 | NET_DUMP_UINT("ifindex", "(%u)", ifindex); 49 | 50 | if (mode == XDP_ATTACHED_MULTI) { 51 | if (json_output) { 52 | jsonw_name(json_wtr, "multi_attachments"); 53 | jsonw_start_array(json_wtr); 54 | } 55 | xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true); 56 | xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true); 57 | xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true); 58 | if (json_output) 59 | jsonw_end_array(json_wtr); 60 | } else if (mode == XDP_ATTACHED_DRV) { 61 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false); 62 | } else if (mode == XDP_ATTACHED_SKB) { 63 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false); 64 | } else if (mode == XDP_ATTACHED_HW) { 65 | xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false); 66 | } 67 | 68 | NET_END_OBJECT_FINAL; 69 | return 0; 70 | } 71 | 72 | int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb) 73 | { 74 | if (!tb[IFLA_XDP]) 75 | return 0; 76 | 77 | return do_xdp_dump_one(tb[IFLA_XDP], (unsigned int)ifinfo->ifi_index, 78 | libbpf_nla_getattr_str(tb[IFLA_IFNAME])); 79 | } 80 | 81 | static int do_bpf_dump_one_act(struct nlattr *attr) 82 | { 83 | struct nlattr *tb[TCA_ACT_BPF_MAX + 1]; 84 | 85 | if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0) 86 | return -LIBBPF_ERRNO__NLPARSE; 87 | 88 | if (!tb[TCA_ACT_BPF_PARMS]) 89 | return -LIBBPF_ERRNO__NLPARSE; 90 | 91 | NET_START_OBJECT_NESTED2; 92 | if (tb[TCA_ACT_BPF_NAME]) 93 | NET_DUMP_STR("name", "%s", 94 | libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME])); 95 | if (tb[TCA_ACT_BPF_ID]) 96 | NET_DUMP_UINT("id", " id %u", 97 | libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID])); 98 | NET_END_OBJECT_NESTED; 99 | return 0; 100 | } 101 | 102 | static int do_dump_one_act(struct nlattr *attr) 103 | { 104 | struct nlattr *tb[TCA_ACT_MAX + 1]; 105 | 106 | if (!attr) 107 | return 0; 108 | 109 | if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0) 110 | return -LIBBPF_ERRNO__NLPARSE; 111 | 112 | if (tb[TCA_ACT_KIND] && 113 | strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0) 114 | return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]); 115 | 116 | return 0; 117 | } 118 | 119 | static int do_bpf_act_dump(struct nlattr *attr) 120 | { 121 | struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; 122 | int act, ret; 123 | 124 | if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0) 125 | return -LIBBPF_ERRNO__NLPARSE; 126 | 127 | NET_START_ARRAY("act", " %s ["); 128 | for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) { 129 | ret = do_dump_one_act(tb[act]); 130 | if (ret) 131 | break; 132 | } 133 | NET_END_ARRAY("] "); 134 | 135 | return ret; 136 | } 137 | 138 | static int do_bpf_filter_dump(struct nlattr *attr) 139 | { 140 | struct nlattr *tb[TCA_BPF_MAX + 1]; 141 | int ret; 142 | 143 | if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0) 144 | return -LIBBPF_ERRNO__NLPARSE; 145 | 146 | if (tb[TCA_BPF_NAME]) 147 | NET_DUMP_STR("name", " %s", 148 | libbpf_nla_getattr_str(tb[TCA_BPF_NAME])); 149 | if (tb[TCA_BPF_ID]) 150 | NET_DUMP_UINT("id", " id %u", 151 | libbpf_nla_getattr_u32(tb[TCA_BPF_ID])); 152 | if (tb[TCA_BPF_ACT]) { 153 | ret = do_bpf_act_dump(tb[TCA_BPF_ACT]); 154 | if (ret) 155 | return ret; 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind, 162 | const char *devname, int ifindex) 163 | { 164 | int ret = 0; 165 | 166 | if (tb[TCA_OPTIONS] && 167 | strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) { 168 | NET_START_OBJECT; 169 | if (devname[0] != '\0') 170 | NET_DUMP_STR("devname", "%s", devname); 171 | NET_DUMP_UINT("ifindex", "(%u)", (unsigned int)ifindex); 172 | NET_DUMP_STR("kind", " %s", kind); 173 | ret = do_bpf_filter_dump(tb[TCA_OPTIONS]); 174 | NET_END_OBJECT_FINAL; 175 | } 176 | 177 | return ret; 178 | } 179 | -------------------------------------------------------------------------------- /src/netlink_dumper.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | // Copyright (C) 2018 Facebook 3 | 4 | #ifndef _NETLINK_DUMPER_H_ 5 | #define _NETLINK_DUMPER_H_ 6 | 7 | #define NET_START_OBJECT \ 8 | { \ 9 | if (json_output) \ 10 | jsonw_start_object(json_wtr); \ 11 | } 12 | 13 | #define NET_START_OBJECT_NESTED(name) \ 14 | { \ 15 | if (json_output) { \ 16 | jsonw_name(json_wtr, name); \ 17 | jsonw_start_object(json_wtr); \ 18 | } else { \ 19 | fprintf(stdout, "%s {", name); \ 20 | } \ 21 | } 22 | 23 | #define NET_START_OBJECT_NESTED2 \ 24 | { \ 25 | if (json_output) \ 26 | jsonw_start_object(json_wtr); \ 27 | else \ 28 | fprintf(stdout, "{"); \ 29 | } 30 | 31 | #define NET_END_OBJECT_NESTED \ 32 | { \ 33 | if (json_output) \ 34 | jsonw_end_object(json_wtr); \ 35 | else \ 36 | fprintf(stdout, "}"); \ 37 | } 38 | 39 | #define NET_END_OBJECT \ 40 | { \ 41 | if (json_output) \ 42 | jsonw_end_object(json_wtr); \ 43 | } 44 | 45 | #define NET_END_OBJECT_FINAL \ 46 | { \ 47 | if (json_output) \ 48 | jsonw_end_object(json_wtr); \ 49 | else \ 50 | fprintf(stdout, "\n"); \ 51 | } 52 | 53 | #define NET_START_ARRAY(name, fmt_str) \ 54 | { \ 55 | if (json_output) { \ 56 | jsonw_name(json_wtr, name); \ 57 | jsonw_start_array(json_wtr); \ 58 | } else { \ 59 | fprintf(stdout, fmt_str, name); \ 60 | } \ 61 | } 62 | 63 | #define NET_END_ARRAY(endstr) \ 64 | { \ 65 | if (json_output) \ 66 | jsonw_end_array(json_wtr); \ 67 | else \ 68 | fprintf(stdout, "%s", endstr); \ 69 | } 70 | 71 | #define NET_DUMP_UINT(name, fmt_str, val) \ 72 | { \ 73 | if (json_output) \ 74 | jsonw_uint_field(json_wtr, name, val); \ 75 | else \ 76 | fprintf(stdout, fmt_str, val); \ 77 | } 78 | 79 | #define NET_DUMP_UINT_ONLY(str) \ 80 | { \ 81 | if (json_output) \ 82 | jsonw_uint(json_wtr, str); \ 83 | else \ 84 | fprintf(stdout, "%u ", str); \ 85 | } 86 | 87 | #define NET_DUMP_STR(name, fmt_str, str) \ 88 | { \ 89 | if (json_output) \ 90 | jsonw_string_field(json_wtr, name, str);\ 91 | else \ 92 | fprintf(stdout, fmt_str, str); \ 93 | } 94 | 95 | #define NET_DUMP_STR_ONLY(str) \ 96 | { \ 97 | if (json_output) \ 98 | jsonw_string(json_wtr, str); \ 99 | else \ 100 | fprintf(stdout, "%s ", str); \ 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/perf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | // Copyright (C) 2018 Facebook 3 | // Author: Yonghong Song 4 | 5 | #ifndef _GNU_SOURCE 6 | #define _GNU_SOURCE 7 | #endif 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include "main.h" 21 | 22 | /* 0: undecided, 1: supported, 2: not supported */ 23 | static int perf_query_supported; 24 | static bool has_perf_query_support(void) 25 | { 26 | __u64 probe_offset, probe_addr; 27 | __u32 len, prog_id, fd_type; 28 | char buf[256]; 29 | int fd; 30 | 31 | if (perf_query_supported) 32 | goto out; 33 | 34 | fd = open("/", O_RDONLY); 35 | if (fd < 0) { 36 | p_err("perf_query_support: cannot open directory \"/\" (%s)", 37 | strerror(errno)); 38 | goto out; 39 | } 40 | 41 | /* the following query will fail as no bpf attachment, 42 | * the expected errno is ENOTSUPP 43 | */ 44 | errno = 0; 45 | len = sizeof(buf); 46 | bpf_task_fd_query(getpid(), fd, 0, buf, &len, &prog_id, 47 | &fd_type, &probe_offset, &probe_addr); 48 | 49 | if (errno == 524 /* ENOTSUPP */) { 50 | perf_query_supported = 1; 51 | goto close_fd; 52 | } 53 | 54 | perf_query_supported = 2; 55 | p_err("perf_query_support: %s", strerror(errno)); 56 | fprintf(stderr, 57 | "HINT: non root or kernel doesn't support TASK_FD_QUERY\n"); 58 | 59 | close_fd: 60 | close(fd); 61 | out: 62 | return perf_query_supported == 1; 63 | } 64 | 65 | static void print_perf_json(int pid, int fd, __u32 prog_id, __u32 fd_type, 66 | char *buf, __u64 probe_offset, __u64 probe_addr) 67 | { 68 | jsonw_start_object(json_wtr); 69 | jsonw_int_field(json_wtr, "pid", pid); 70 | jsonw_int_field(json_wtr, "fd", fd); 71 | jsonw_uint_field(json_wtr, "prog_id", prog_id); 72 | switch (fd_type) { 73 | case BPF_FD_TYPE_RAW_TRACEPOINT: 74 | jsonw_string_field(json_wtr, "fd_type", "raw_tracepoint"); 75 | jsonw_string_field(json_wtr, "tracepoint", buf); 76 | break; 77 | case BPF_FD_TYPE_TRACEPOINT: 78 | jsonw_string_field(json_wtr, "fd_type", "tracepoint"); 79 | jsonw_string_field(json_wtr, "tracepoint", buf); 80 | break; 81 | case BPF_FD_TYPE_KPROBE: 82 | jsonw_string_field(json_wtr, "fd_type", "kprobe"); 83 | if (buf[0] != '\0') { 84 | jsonw_string_field(json_wtr, "func", buf); 85 | jsonw_lluint_field(json_wtr, "offset", probe_offset); 86 | } else { 87 | jsonw_lluint_field(json_wtr, "addr", probe_addr); 88 | } 89 | break; 90 | case BPF_FD_TYPE_KRETPROBE: 91 | jsonw_string_field(json_wtr, "fd_type", "kretprobe"); 92 | if (buf[0] != '\0') { 93 | jsonw_string_field(json_wtr, "func", buf); 94 | jsonw_lluint_field(json_wtr, "offset", probe_offset); 95 | } else { 96 | jsonw_lluint_field(json_wtr, "addr", probe_addr); 97 | } 98 | break; 99 | case BPF_FD_TYPE_UPROBE: 100 | jsonw_string_field(json_wtr, "fd_type", "uprobe"); 101 | jsonw_string_field(json_wtr, "filename", buf); 102 | jsonw_lluint_field(json_wtr, "offset", probe_offset); 103 | break; 104 | case BPF_FD_TYPE_URETPROBE: 105 | jsonw_string_field(json_wtr, "fd_type", "uretprobe"); 106 | jsonw_string_field(json_wtr, "filename", buf); 107 | jsonw_lluint_field(json_wtr, "offset", probe_offset); 108 | break; 109 | default: 110 | break; 111 | } 112 | jsonw_end_object(json_wtr); 113 | } 114 | 115 | static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type, 116 | char *buf, __u64 probe_offset, __u64 probe_addr) 117 | { 118 | printf("pid %d fd %d: prog_id %u ", pid, fd, prog_id); 119 | switch (fd_type) { 120 | case BPF_FD_TYPE_RAW_TRACEPOINT: 121 | printf("raw_tracepoint %s\n", buf); 122 | break; 123 | case BPF_FD_TYPE_TRACEPOINT: 124 | printf("tracepoint %s\n", buf); 125 | break; 126 | case BPF_FD_TYPE_KPROBE: 127 | if (buf[0] != '\0') 128 | printf("kprobe func %s offset %llu\n", buf, 129 | probe_offset); 130 | else 131 | printf("kprobe addr %llu\n", probe_addr); 132 | break; 133 | case BPF_FD_TYPE_KRETPROBE: 134 | if (buf[0] != '\0') 135 | printf("kretprobe func %s offset %llu\n", buf, 136 | probe_offset); 137 | else 138 | printf("kretprobe addr %llu\n", probe_addr); 139 | break; 140 | case BPF_FD_TYPE_UPROBE: 141 | printf("uprobe filename %s offset %llu\n", buf, probe_offset); 142 | break; 143 | case BPF_FD_TYPE_URETPROBE: 144 | printf("uretprobe filename %s offset %llu\n", buf, 145 | probe_offset); 146 | break; 147 | default: 148 | break; 149 | } 150 | } 151 | 152 | static int show_proc(void) 153 | { 154 | struct dirent *proc_de, *pid_fd_de; 155 | __u64 probe_offset, probe_addr; 156 | __u32 len, prog_id, fd_type; 157 | DIR *proc, *pid_fd; 158 | int err, pid, fd; 159 | const char *pch; 160 | char buf[4096]; 161 | 162 | proc = opendir("/proc"); 163 | if (!proc) 164 | return -1; 165 | 166 | while ((proc_de = readdir(proc))) { 167 | pid = 0; 168 | pch = proc_de->d_name; 169 | 170 | /* pid should be all numbers */ 171 | while (isdigit(*pch)) { 172 | pid = pid * 10 + *pch - '0'; 173 | pch++; 174 | } 175 | if (*pch != '\0') 176 | continue; 177 | 178 | err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name); 179 | if (err < 0 || err >= (int)sizeof(buf)) 180 | continue; 181 | 182 | pid_fd = opendir(buf); 183 | if (!pid_fd) 184 | continue; 185 | 186 | while ((pid_fd_de = readdir(pid_fd))) { 187 | fd = 0; 188 | pch = pid_fd_de->d_name; 189 | 190 | /* fd should be all numbers */ 191 | while (isdigit(*pch)) { 192 | fd = fd * 10 + *pch - '0'; 193 | pch++; 194 | } 195 | if (*pch != '\0') 196 | continue; 197 | 198 | /* query (pid, fd) for potential perf events */ 199 | len = sizeof(buf); 200 | err = bpf_task_fd_query(pid, fd, 0, buf, &len, 201 | &prog_id, &fd_type, 202 | &probe_offset, &probe_addr); 203 | if (err < 0) 204 | continue; 205 | 206 | if (json_output) 207 | print_perf_json(pid, fd, prog_id, fd_type, buf, 208 | probe_offset, probe_addr); 209 | else 210 | print_perf_plain(pid, fd, prog_id, fd_type, buf, 211 | probe_offset, probe_addr); 212 | } 213 | closedir(pid_fd); 214 | } 215 | closedir(proc); 216 | return 0; 217 | } 218 | 219 | static int do_show(int argc, char **argv) 220 | { 221 | int err; 222 | 223 | if (!has_perf_query_support()) 224 | return -1; 225 | 226 | if (json_output) 227 | jsonw_start_array(json_wtr); 228 | err = show_proc(); 229 | if (json_output) 230 | jsonw_end_array(json_wtr); 231 | 232 | return err; 233 | } 234 | 235 | static int do_help(int argc, char **argv) 236 | { 237 | fprintf(stderr, 238 | "Usage: %1$s %2$s { show | list }\n" 239 | " %1$s %2$s help\n" 240 | "\n" 241 | " " HELP_SPEC_OPTIONS " }\n" 242 | "", 243 | bin_name, argv[-2]); 244 | 245 | return 0; 246 | } 247 | 248 | static const struct cmd cmds[] = { 249 | { "show", do_show }, 250 | { "list", do_show }, 251 | { "help", do_help }, 252 | { 0 } 253 | }; 254 | 255 | int do_perf(int argc, char **argv) 256 | { 257 | return cmd_select(cmds, argc, argv, do_help); 258 | } 259 | -------------------------------------------------------------------------------- /src/pids.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | /* Copyright (C) 2020 Facebook */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "main.h" 15 | #include "skeleton/pid_iter.h" 16 | 17 | #ifdef BPFTOOL_WITHOUT_SKELETONS 18 | 19 | int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type) 20 | { 21 | return -ENOTSUP; 22 | } 23 | void delete_obj_refs_table(struct hashmap *map) {} 24 | void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) {} 25 | void emit_obj_refs_json(struct hashmap *map, __u32 id, json_writer_t *json_writer) {} 26 | 27 | #else /* BPFTOOL_WITHOUT_SKELETONS */ 28 | 29 | #include "pid_iter.skel.h" 30 | 31 | static void add_ref(struct hashmap *map, struct pid_iter_entry *e) 32 | { 33 | struct hashmap_entry *entry; 34 | struct obj_refs *refs; 35 | struct obj_ref *ref; 36 | int err, i; 37 | void *tmp; 38 | 39 | hashmap__for_each_key_entry(map, entry, e->id) { 40 | refs = entry->pvalue; 41 | 42 | for (i = 0; i < refs->ref_cnt; i++) { 43 | if (refs->refs[i].pid == e->pid) 44 | return; 45 | } 46 | 47 | tmp = realloc(refs->refs, (refs->ref_cnt + 1) * sizeof(*ref)); 48 | if (!tmp) { 49 | p_err("failed to re-alloc memory for ID %u, PID %d, COMM %s...", 50 | e->id, e->pid, e->comm); 51 | return; 52 | } 53 | refs->refs = tmp; 54 | ref = &refs->refs[refs->ref_cnt]; 55 | ref->pid = e->pid; 56 | memcpy(ref->comm, e->comm, sizeof(ref->comm)); 57 | ref->comm[sizeof(ref->comm) - 1] = '\0'; 58 | refs->ref_cnt++; 59 | 60 | return; 61 | } 62 | 63 | /* new ref */ 64 | refs = calloc(1, sizeof(*refs)); 65 | if (!refs) { 66 | p_err("failed to alloc memory for ID %u, PID %d, COMM %s...", 67 | e->id, e->pid, e->comm); 68 | return; 69 | } 70 | 71 | refs->refs = malloc(sizeof(*refs->refs)); 72 | if (!refs->refs) { 73 | free(refs); 74 | p_err("failed to alloc memory for ID %u, PID %d, COMM %s...", 75 | e->id, e->pid, e->comm); 76 | return; 77 | } 78 | ref = &refs->refs[0]; 79 | ref->pid = e->pid; 80 | memcpy(ref->comm, e->comm, sizeof(ref->comm)); 81 | ref->comm[sizeof(ref->comm) - 1] = '\0'; 82 | refs->ref_cnt = 1; 83 | refs->has_bpf_cookie = e->has_bpf_cookie; 84 | refs->bpf_cookie = e->bpf_cookie; 85 | 86 | err = hashmap__append(map, e->id, refs); 87 | if (err) 88 | p_err("failed to append entry to hashmap for ID %u: %s", 89 | e->id, strerror(errno)); 90 | } 91 | 92 | static int __printf(2, 0) 93 | libbpf_print_none(__maybe_unused enum libbpf_print_level level, 94 | __maybe_unused const char *format, 95 | __maybe_unused va_list args) 96 | { 97 | return 0; 98 | } 99 | 100 | int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type) 101 | { 102 | struct pid_iter_entry *e; 103 | char buf[4096 / sizeof(*e) * sizeof(*e)]; 104 | struct pid_iter_bpf *skel; 105 | int err, ret, fd = -1, i; 106 | 107 | *map = hashmap__new(hash_fn_for_key_as_id, equal_fn_for_key_as_id, NULL); 108 | if (IS_ERR(*map)) { 109 | p_err("failed to create hashmap for PID references"); 110 | return -1; 111 | } 112 | set_max_rlimit(); 113 | 114 | skel = pid_iter_bpf__open(); 115 | if (!skel) { 116 | p_err("failed to open PID iterator skeleton"); 117 | return -1; 118 | } 119 | 120 | skel->rodata->obj_type = type; 121 | 122 | if (!verifier_logs) { 123 | libbpf_print_fn_t default_print; 124 | 125 | /* Unless debug information is on, we don't want the output to 126 | * be polluted with libbpf errors if bpf_iter is not supported. 127 | */ 128 | default_print = libbpf_set_print(libbpf_print_none); 129 | err = pid_iter_bpf__load(skel); 130 | libbpf_set_print(default_print); 131 | } else { 132 | err = pid_iter_bpf__load(skel); 133 | } 134 | if (err) { 135 | /* too bad, kernel doesn't support BPF iterators yet */ 136 | err = 0; 137 | goto out; 138 | } 139 | err = pid_iter_bpf__attach(skel); 140 | if (err) { 141 | /* if we loaded above successfully, attach has to succeed */ 142 | p_err("failed to attach PID iterator: %d", err); 143 | goto out; 144 | } 145 | 146 | fd = bpf_iter_create(bpf_link__fd(skel->links.iter)); 147 | if (fd < 0) { 148 | err = -errno; 149 | p_err("failed to create PID iterator session: %d", err); 150 | goto out; 151 | } 152 | 153 | while (true) { 154 | ret = read(fd, buf, sizeof(buf)); 155 | if (ret < 0) { 156 | if (errno == EAGAIN) 157 | continue; 158 | err = -errno; 159 | p_err("failed to read PID iterator output: %d", err); 160 | goto out; 161 | } 162 | if (ret == 0) 163 | break; 164 | if (ret % sizeof(*e)) { 165 | err = -EINVAL; 166 | p_err("invalid PID iterator output format"); 167 | goto out; 168 | } 169 | ret /= sizeof(*e); 170 | 171 | e = (void *)buf; 172 | for (i = 0; i < ret; i++, e++) { 173 | add_ref(*map, e); 174 | } 175 | } 176 | err = 0; 177 | out: 178 | if (fd >= 0) 179 | close(fd); 180 | pid_iter_bpf__destroy(skel); 181 | return err; 182 | } 183 | 184 | void delete_obj_refs_table(struct hashmap *map) 185 | { 186 | struct hashmap_entry *entry; 187 | size_t bkt; 188 | 189 | if (!map) 190 | return; 191 | 192 | hashmap__for_each_entry(map, entry, bkt) { 193 | struct obj_refs *refs = entry->pvalue; 194 | 195 | free(refs->refs); 196 | free(refs); 197 | } 198 | 199 | hashmap__free(map); 200 | } 201 | 202 | void emit_obj_refs_json(struct hashmap *map, __u32 id, 203 | json_writer_t *json_writer) 204 | { 205 | struct hashmap_entry *entry; 206 | 207 | if (hashmap__empty(map)) 208 | return; 209 | 210 | hashmap__for_each_key_entry(map, entry, id) { 211 | struct obj_refs *refs = entry->pvalue; 212 | int i; 213 | 214 | if (refs->ref_cnt == 0) 215 | break; 216 | 217 | if (refs->has_bpf_cookie) 218 | jsonw_lluint_field(json_writer, "bpf_cookie", refs->bpf_cookie); 219 | 220 | jsonw_name(json_writer, "pids"); 221 | jsonw_start_array(json_writer); 222 | for (i = 0; i < refs->ref_cnt; i++) { 223 | struct obj_ref *ref = &refs->refs[i]; 224 | 225 | jsonw_start_object(json_writer); 226 | jsonw_int_field(json_writer, "pid", ref->pid); 227 | jsonw_string_field(json_writer, "comm", ref->comm); 228 | jsonw_end_object(json_writer); 229 | } 230 | jsonw_end_array(json_writer); 231 | break; 232 | } 233 | } 234 | 235 | void emit_obj_refs_plain(struct hashmap *map, __u32 id, const char *prefix) 236 | { 237 | struct hashmap_entry *entry; 238 | 239 | if (hashmap__empty(map)) 240 | return; 241 | 242 | hashmap__for_each_key_entry(map, entry, id) { 243 | struct obj_refs *refs = entry->pvalue; 244 | int i; 245 | 246 | if (refs->ref_cnt == 0) 247 | break; 248 | 249 | if (refs->has_bpf_cookie) 250 | printf("\n\tbpf_cookie %llu", (unsigned long long) refs->bpf_cookie); 251 | 252 | printf("%s", prefix); 253 | for (i = 0; i < refs->ref_cnt; i++) { 254 | struct obj_ref *ref = &refs->refs[i]; 255 | 256 | printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid); 257 | } 258 | break; 259 | } 260 | } 261 | 262 | 263 | #endif 264 | -------------------------------------------------------------------------------- /src/skeleton/pid_iter.bpf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | /* Copyright (c) 2020 Facebook */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "pid_iter.h" 8 | 9 | /* keep in sync with the definition in main.h */ 10 | enum bpf_obj_type { 11 | BPF_OBJ_UNKNOWN, 12 | BPF_OBJ_PROG, 13 | BPF_OBJ_MAP, 14 | BPF_OBJ_LINK, 15 | BPF_OBJ_BTF, 16 | }; 17 | 18 | struct bpf_perf_link___local { 19 | struct bpf_link link; 20 | struct file *perf_file; 21 | } __attribute__((preserve_access_index)); 22 | 23 | struct perf_event___local { 24 | u64 bpf_cookie; 25 | } __attribute__((preserve_access_index)); 26 | 27 | enum bpf_link_type___local { 28 | BPF_LINK_TYPE_PERF_EVENT___local = 7, 29 | }; 30 | 31 | extern const void bpf_link_fops __ksym; 32 | extern const void bpf_link_fops_poll __ksym __weak; 33 | extern const void bpf_map_fops __ksym; 34 | extern const void bpf_prog_fops __ksym; 35 | extern const void btf_fops __ksym; 36 | 37 | const volatile enum bpf_obj_type obj_type = BPF_OBJ_UNKNOWN; 38 | 39 | static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type) 40 | { 41 | switch (type) { 42 | case BPF_OBJ_PROG: 43 | return BPF_CORE_READ((struct bpf_prog *)ent, aux, id); 44 | case BPF_OBJ_MAP: 45 | return BPF_CORE_READ((struct bpf_map *)ent, id); 46 | case BPF_OBJ_BTF: 47 | return BPF_CORE_READ((struct btf *)ent, id); 48 | case BPF_OBJ_LINK: 49 | return BPF_CORE_READ((struct bpf_link *)ent, id); 50 | default: 51 | return 0; 52 | } 53 | } 54 | 55 | /* could be used only with BPF_LINK_TYPE_PERF_EVENT links */ 56 | static __u64 get_bpf_cookie(struct bpf_link *link) 57 | { 58 | struct bpf_perf_link___local *perf_link; 59 | struct perf_event___local *event; 60 | 61 | perf_link = container_of(link, struct bpf_perf_link___local, link); 62 | event = BPF_CORE_READ(perf_link, perf_file, private_data); 63 | return BPF_CORE_READ(event, bpf_cookie); 64 | } 65 | 66 | SEC("iter/task_file") 67 | int iter(struct bpf_iter__task_file *ctx) 68 | { 69 | struct file *file = ctx->file; 70 | struct task_struct *task = ctx->task; 71 | struct pid_iter_entry e; 72 | const void *fops; 73 | 74 | if (!file || !task) 75 | return 0; 76 | 77 | switch (obj_type) { 78 | case BPF_OBJ_PROG: 79 | fops = &bpf_prog_fops; 80 | break; 81 | case BPF_OBJ_MAP: 82 | fops = &bpf_map_fops; 83 | break; 84 | case BPF_OBJ_BTF: 85 | fops = &btf_fops; 86 | break; 87 | case BPF_OBJ_LINK: 88 | if (&bpf_link_fops_poll && 89 | file->f_op == &bpf_link_fops_poll) 90 | fops = &bpf_link_fops_poll; 91 | else 92 | fops = &bpf_link_fops; 93 | break; 94 | default: 95 | return 0; 96 | } 97 | 98 | if (file->f_op != fops) 99 | return 0; 100 | 101 | __builtin_memset(&e, 0, sizeof(e)); 102 | e.pid = task->tgid; 103 | e.id = get_obj_id(file->private_data, obj_type); 104 | 105 | if (obj_type == BPF_OBJ_LINK && 106 | bpf_core_enum_value_exists(enum bpf_link_type___local, 107 | BPF_LINK_TYPE_PERF_EVENT___local)) { 108 | struct bpf_link *link = (struct bpf_link *) file->private_data; 109 | 110 | if (BPF_CORE_READ(link, type) == bpf_core_enum_value(enum bpf_link_type___local, 111 | BPF_LINK_TYPE_PERF_EVENT___local)) { 112 | e.has_bpf_cookie = true; 113 | e.bpf_cookie = get_bpf_cookie(link); 114 | } 115 | } 116 | 117 | bpf_probe_read_kernel_str(&e.comm, sizeof(e.comm), 118 | task->group_leader->comm); 119 | bpf_seq_write(ctx->meta->seq, &e, sizeof(e)); 120 | 121 | return 0; 122 | } 123 | 124 | char LICENSE[] SEC("license") = "Dual BSD/GPL"; 125 | -------------------------------------------------------------------------------- /src/skeleton/pid_iter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (c) 2020 Facebook */ 3 | #ifndef __PID_ITER_H 4 | #define __PID_ITER_H 5 | 6 | struct pid_iter_entry { 7 | __u32 id; 8 | int pid; 9 | __u64 bpf_cookie; 10 | bool has_bpf_cookie; 11 | char comm[16]; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/skeleton/profiler.bpf.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | // Copyright (c) 2020 Facebook 3 | #include 4 | #include 5 | #include 6 | 7 | struct bpf_perf_event_value___local { 8 | __u64 counter; 9 | __u64 enabled; 10 | __u64 running; 11 | } __attribute__((preserve_access_index)); 12 | 13 | /* map of perf event fds, num_cpu * num_metric entries */ 14 | struct { 15 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 16 | __uint(key_size, sizeof(u32)); 17 | __uint(value_size, sizeof(int)); 18 | } events SEC(".maps"); 19 | 20 | /* readings at fentry */ 21 | struct { 22 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 23 | __uint(key_size, sizeof(u32)); 24 | __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 25 | } fentry_readings SEC(".maps"); 26 | 27 | /* accumulated readings */ 28 | struct { 29 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 30 | __uint(key_size, sizeof(u32)); 31 | __uint(value_size, sizeof(struct bpf_perf_event_value___local)); 32 | } accum_readings SEC(".maps"); 33 | 34 | /* sample counts, one per cpu */ 35 | struct { 36 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 37 | __uint(key_size, sizeof(u32)); 38 | __uint(value_size, sizeof(u64)); 39 | } counts SEC(".maps"); 40 | 41 | const volatile __u32 num_cpu = 1; 42 | const volatile __u32 num_metric = 1; 43 | #define MAX_NUM_METRICS 4 44 | 45 | SEC("fentry/XXX") 46 | int BPF_PROG(fentry_XXX) 47 | { 48 | struct bpf_perf_event_value___local *ptrs[MAX_NUM_METRICS]; 49 | u32 key = bpf_get_smp_processor_id(); 50 | u32 i; 51 | 52 | /* look up before reading, to reduce error */ 53 | for (i = 0; i < num_metric && i < MAX_NUM_METRICS; i++) { 54 | u32 flag = i; 55 | 56 | ptrs[i] = bpf_map_lookup_elem(&fentry_readings, &flag); 57 | if (!ptrs[i]) 58 | return 0; 59 | } 60 | 61 | for (i = 0; i < num_metric && i < MAX_NUM_METRICS; i++) { 62 | struct bpf_perf_event_value___local reading; 63 | int err; 64 | 65 | err = bpf_perf_event_read_value(&events, key, (void *)&reading, 66 | sizeof(reading)); 67 | if (err) 68 | return 0; 69 | *(ptrs[i]) = reading; 70 | key += num_cpu; 71 | } 72 | 73 | return 0; 74 | } 75 | 76 | static inline void 77 | fexit_update_maps(u32 id, struct bpf_perf_event_value___local *after) 78 | { 79 | struct bpf_perf_event_value___local *before, diff; 80 | 81 | before = bpf_map_lookup_elem(&fentry_readings, &id); 82 | /* only account samples with a valid fentry_reading */ 83 | if (before && before->counter) { 84 | struct bpf_perf_event_value___local *accum; 85 | 86 | diff.counter = after->counter - before->counter; 87 | diff.enabled = after->enabled - before->enabled; 88 | diff.running = after->running - before->running; 89 | 90 | accum = bpf_map_lookup_elem(&accum_readings, &id); 91 | if (accum) { 92 | accum->counter += diff.counter; 93 | accum->enabled += diff.enabled; 94 | accum->running += diff.running; 95 | } 96 | } 97 | } 98 | 99 | SEC("fexit/XXX") 100 | int BPF_PROG(fexit_XXX) 101 | { 102 | struct bpf_perf_event_value___local readings[MAX_NUM_METRICS]; 103 | u32 cpu = bpf_get_smp_processor_id(); 104 | u32 i, zero = 0; 105 | int err; 106 | u64 *count; 107 | 108 | /* read all events before updating the maps, to reduce error */ 109 | for (i = 0; i < num_metric && i < MAX_NUM_METRICS; i++) { 110 | err = bpf_perf_event_read_value(&events, cpu + i * num_cpu, 111 | (void *)(readings + i), 112 | sizeof(*readings)); 113 | if (err) 114 | return 0; 115 | } 116 | count = bpf_map_lookup_elem(&counts, &zero); 117 | if (count) { 118 | *count += 1; 119 | for (i = 0; i < num_metric && i < MAX_NUM_METRICS; i++) 120 | fexit_update_maps(i, &readings[i]); 121 | } 122 | return 0; 123 | } 124 | 125 | char LICENSE[] SEC("license") = "Dual BSD/GPL"; 126 | -------------------------------------------------------------------------------- /src/tracelog.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 | /* Copyright (c) 2015-2017 Daniel Borkmann */ 3 | /* Copyright (c) 2018 Netronome Systems, Inc. */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "main.h" 16 | 17 | #ifndef TRACEFS_MAGIC 18 | # define TRACEFS_MAGIC 0x74726163 19 | #endif 20 | 21 | #define _textify(x) #x 22 | #define textify(x) _textify(x) 23 | 24 | FILE *trace_pipe_fd; 25 | char *buff; 26 | 27 | static int validate_tracefs_mnt(const char *mnt, unsigned long magic) 28 | { 29 | struct statfs st_fs; 30 | 31 | if (statfs(mnt, &st_fs) < 0) 32 | return -ENOENT; 33 | if ((unsigned long)st_fs.f_type != magic) 34 | return -ENOENT; 35 | 36 | return 0; 37 | } 38 | 39 | static bool 40 | find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt) 41 | { 42 | size_t src_len; 43 | 44 | if (validate_tracefs_mnt(mntpt, magic)) 45 | return false; 46 | 47 | src_len = strlen(mntpt); 48 | if (src_len + 1 >= PATH_MAX) { 49 | p_err("tracefs mount point name too long"); 50 | return false; 51 | } 52 | 53 | strcpy(mnt, mntpt); 54 | return true; 55 | } 56 | 57 | static bool get_tracefs_pipe(char *mnt) 58 | { 59 | static const char * const known_mnts[] = { 60 | "/sys/kernel/debug/tracing", 61 | "/sys/kernel/tracing", 62 | "/tracing", 63 | "/trace", 64 | }; 65 | const char *pipe_name = "/trace_pipe"; 66 | const char *fstype = "tracefs"; 67 | char type[100], format[32]; 68 | const char * const *ptr; 69 | bool found = false; 70 | FILE *fp; 71 | 72 | for (ptr = known_mnts; ptr < known_mnts + ARRAY_SIZE(known_mnts); ptr++) 73 | if (find_tracefs_mnt_single(TRACEFS_MAGIC, mnt, *ptr)) 74 | goto exit_found; 75 | 76 | fp = fopen("/proc/mounts", "r"); 77 | if (!fp) 78 | return false; 79 | 80 | /* Allow room for NULL terminating byte and pipe file name */ 81 | snprintf(format, sizeof(format), "%%*s %%%zus %%99s %%*s %%*d %%*d\\n", 82 | PATH_MAX - strlen(pipe_name) - 1); 83 | while (fscanf(fp, format, mnt, type) == 2) 84 | if (strcmp(type, fstype) == 0) { 85 | found = true; 86 | break; 87 | } 88 | fclose(fp); 89 | 90 | /* The string from fscanf() might be truncated, check mnt is valid */ 91 | if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) 92 | goto exit_found; 93 | 94 | if (block_mount) 95 | return false; 96 | 97 | p_info("could not find tracefs, attempting to mount it now"); 98 | /* Most of the time, tracefs is automatically mounted by debugfs at 99 | * /sys/kernel/debug/tracing when we try to access it. If we could not 100 | * find it, it is likely that debugfs is not mounted. Let's give one 101 | * attempt at mounting just tracefs at /sys/kernel/tracing. 102 | */ 103 | strcpy(mnt, known_mnts[1]); 104 | if (mount_tracefs(mnt)) 105 | return false; 106 | 107 | exit_found: 108 | strcat(mnt, pipe_name); 109 | return true; 110 | } 111 | 112 | static void exit_tracelog(int signum) 113 | { 114 | fclose(trace_pipe_fd); 115 | free(buff); 116 | 117 | if (json_output) { 118 | jsonw_end_array(json_wtr); 119 | jsonw_destroy(&json_wtr); 120 | } 121 | 122 | exit(0); 123 | } 124 | 125 | int do_tracelog(int argc, char **argv) 126 | { 127 | const struct sigaction act = { 128 | .sa_handler = exit_tracelog 129 | }; 130 | char trace_pipe[PATH_MAX]; 131 | size_t buff_len = 0; 132 | 133 | if (json_output) 134 | jsonw_start_array(json_wtr); 135 | 136 | if (!get_tracefs_pipe(trace_pipe)) 137 | return -1; 138 | 139 | trace_pipe_fd = fopen(trace_pipe, "r"); 140 | if (!trace_pipe_fd) { 141 | p_err("could not open trace pipe: %s", strerror(errno)); 142 | return -1; 143 | } 144 | 145 | sigaction(SIGHUP, &act, NULL); 146 | sigaction(SIGINT, &act, NULL); 147 | sigaction(SIGTERM, &act, NULL); 148 | while (1) { 149 | ssize_t ret; 150 | 151 | ret = getline(&buff, &buff_len, trace_pipe_fd); 152 | if (ret <= 0) { 153 | p_err("failed to read content from trace pipe: %s", 154 | strerror(errno)); 155 | break; 156 | } 157 | if (json_output) 158 | jsonw_string(json_wtr, buff); 159 | else 160 | printf("%s", buff); 161 | } 162 | 163 | fclose(trace_pipe_fd); 164 | free(buff); 165 | return -1; 166 | } 167 | -------------------------------------------------------------------------------- /src/xlated_dumper.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (C) 2018 Netronome Systems, Inc. */ 3 | 4 | #ifndef __BPF_TOOL_XLATED_DUMPER_H 5 | #define __BPF_TOOL_XLATED_DUMPER_H 6 | 7 | #define SYM_MAX_NAME 256 8 | #define MODULE_MAX_NAME 64 9 | 10 | struct bpf_prog_linfo; 11 | 12 | struct kernel_sym { 13 | unsigned long address; 14 | char name[SYM_MAX_NAME]; 15 | char module[MODULE_MAX_NAME]; 16 | }; 17 | 18 | struct dump_data { 19 | unsigned long address_call_base; 20 | struct kernel_sym *sym_mapping; 21 | __u32 sym_count; 22 | __u64 *jited_ksyms; 23 | __u32 nr_jited_ksyms; 24 | struct btf *btf; 25 | void *func_info; 26 | __u32 finfo_rec_size; 27 | const struct bpf_prog_linfo *prog_linfo; 28 | char scratch_buff[SYM_MAX_NAME + 8]; 29 | }; 30 | 31 | void kernel_syms_load(struct dump_data *dd); 32 | void kernel_syms_destroy(struct dump_data *dd); 33 | struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key); 34 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, 35 | bool opcodes, bool linum); 36 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, 37 | bool opcodes, bool linum); 38 | void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end, 39 | unsigned int start_index, 40 | bool opcodes, bool linum); 41 | 42 | #endif 43 | --------------------------------------------------------------------------------