diff --git a/.dockerignore b/.dockerignore index b14e9c2ea..8ce85d095 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,5 @@ .cache +.git go +tools/coredump/gdb-sysroot +tools/coredump/modulecache diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2e8e641bd..2a044e5e1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,7 +28,7 @@ jobs: uses: ./.github/workflows/env - name: Initialize CodeQL - uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: languages: go @@ -37,7 +37,7 @@ jobs: make TARGET_ARCH=${{ matrix.target_arch }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: category: "/language:Go" timeout-minutes: 10 diff --git a/.github/workflows/collector-tests.yml b/.github/workflows/collector-tests.yml new file mode 100644 index 000000000..326d575ed --- /dev/null +++ b/.github/workflows/collector-tests.yml @@ -0,0 +1,50 @@ +name: Collector Tests +on: + workflow_dispatch: + schedule: + # Run every day at 3:15 AM. + - cron: '15 3 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +permissions: + contents: read + issues: write + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Set up environment + uses: ./.github/workflows/env + with: + skip_rust: true + - name: Cache coredump modules + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: tools/coredump/modulecache + key: coredumps-collector-${{ hashFiles('tools/coredump/testdata/*/*.json') }} + restore-keys: | + coredumps-collector + coredumps- + - name: Clone Collector + run: | + collector_path=/tmp/opentelemetry-collector + git clone --depth=1 https://github.com/open-telemetry/opentelemetry-collector.git $collector_path + - name: Setup replace statement + run: | + COLLECTOR_PATH=/tmp/opentelemetry-collector ./scripts/local-collector.sh + go mod tidy + - name: Tests + run: make test-junit + - name: Generate Issue + if: failure() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + go install go.opentelemetry.io/build-tools/issuegenerator@latest + issuegenerator -path /tmp/testresults diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 0cecf8015..34af9fa08 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -42,6 +42,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5 with: sarif_file: results.sarif diff --git a/.github/workflows/unit-test-on-pull-request.yml b/.github/workflows/unit-test-on-pull-request.yml index ba4eb4fa2..99c734632 100644 --- a/.github/workflows/unit-test-on-pull-request.yml +++ b/.github/workflows/unit-test-on-pull-request.yml @@ -90,7 +90,7 @@ jobs: check-binary-blobs: name: Check for differences in the eBPF binary blobs runs-on: ubuntu-24.04 - container: otel/opentelemetry-ebpf-profiler-dev:latest@sha256:acce547f366150eb25392e1aff270df430ef6b759baeb4292999116018e70e6e + container: otel/opentelemetry-ebpf-profiler-dev:latest@sha256:db6081344e85ef95317b19dbf667d56df35812353b23d0fd54e1db0f55436b80 defaults: run: shell: bash --login {0} diff --git a/.gitignore b/.gitignore index 8e11b42e0..66e923a2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o +*.d *.pb.go .cache /.idea diff --git a/Cargo.lock b/Cargo.lock index 5e8062232..517cf8d4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,9 +462,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustix" @@ -507,9 +507,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", diff --git a/Dockerfile b/Dockerfile index 8bec94427..c16d66a7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:testing-20241223-slim@sha256:2ed89b1e8012d945cfcc111fa1dc11a628edaa24b9af5d63d6935b5ee35d3377 +FROM debian:testing-20250721-slim@sha256:aaa28744f5b892a7ccc3e97c0e9b9cdd0fcc447227efaf9e54080801b990f973 WORKDIR /agent @@ -12,7 +12,7 @@ RUN cross_debian_arch=$(uname -m | sed -e 's/aarch64/amd64/' -e 's/x86_64/arm64 apt-get dist-upgrade -y && \ apt-get install -y --no-install-recommends --no-install-suggests \ curl wget make git cmake unzip libc6-dev g++ gcc pkgconf \ - clang-17 clang-format-17 \ + llvm-17 clang-17 clang-format-17 ca-certificates \ gcc-${cross_pkg_arch}-linux-gnu libc6-${cross_debian_arch}-cross \ musl-dev:amd64 musl-dev:arm64 && \ apt-get clean autoclean && \ @@ -47,6 +47,7 @@ RUN # Append to /etc/profile for login shells RUN echo 'export PATH="/usr/local/go/bin:$PATH"' >> /etc/profile +RUN echo 'export PATH="/agent/go/bin:$PATH"' >> /etc/profile # Create rust related directories in /usr/local RUN mkdir -p /usr/local/cargo /usr/local/rustup diff --git a/Makefile b/Makefile index 42c87ad25..b87768f0d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ -.PHONY: all all-common clean ebpf generate test test-deps protobuf docker-image agent legal \ - integration-test-binaries codespell lint linter-version debug debug-agent ebpf-profiler \ - format-ebpf rust-components rust-targets rust-tests vanity-import-check vanity-import-fix +.PHONY: all all-common clean ebpf generate test test-deps \ + test-junit protobuf docker-image agent legal integration-test-binaries \ + codespell lint linter-version debug debug-agent ebpf-profiler format-ebpf \ + rust-components rust-targets rust-tests vanity-import-check vanity-import-fix SHELL := /usr/bin/env bash @@ -49,6 +50,8 @@ GO_FLAGS := -buildvcs=false -ldflags="$(LDFLAGS)" MAKEFLAGS += -j$(shell nproc) +JUNIT_OUT_DIR ?= /tmp/testresults + all: ebpf-profiler debug: GO_TAGS := $(GO_TAGS),debugtracer @@ -106,6 +109,11 @@ test: generate ebpf test-deps # tools/coredump tests build ebpf C-code using CGO to test it against coredumps CGO_ENABLED=1 go test $(GO_FLAGS) -tags $(GO_TAGS) ./... +test-junit: generate ebpf test-deps + mkdir -p $(JUNIT_OUT_DIR) + go install gotest.tools/gotestsum@latest + CGO_ENABLED=1 gotestsum --junitfile $(JUNIT_OUT_DIR)/junit.xml -- $(GO_FLAGS) -tags $(GO_TAGS) ./... + # This target isn't called from CI, it doesn't work for cross compile (ie TARGET_ARCH=arm64 on # amd64) and the CI kernel tests run them already. Useful for local testing. sudo-golabels-test: integration-test-binaries diff --git a/armhelpers/arm_helpers.go b/armhelpers/arm_helpers.go index 41b7d10ac..4887575f3 100644 --- a/armhelpers/arm_helpers.go +++ b/armhelpers/arm_helpers.go @@ -15,7 +15,7 @@ import ( // Xreg2num converts arm64asm Reg or RegSP X0...X30 and W0...W30 register enum into a register // number. X0/W0 return 0, X1/W1 return 1, etc. -func Xreg2num(arg interface{}) (int, bool) { +func Xreg2num(arg any) (int, bool) { var ndx aa.Reg switch reg := arg.(type) { case aa.Reg: diff --git a/asm/amd/interpreter.go b/asm/amd/interpreter.go index fca2dd37b..37560d3b4 100644 --- a/asm/amd/interpreter.go +++ b/asm/amd/interpreter.go @@ -173,7 +173,7 @@ func (i *Interpreter) MemArg(src x86asm.Mem) expression.Expression { } func (i *Interpreter) initRegs() { - for j := 0; j < len(i.Regs.regs); j++ { + for j := range len(i.Regs.regs) { i.Regs.regs[j] = expression.Named(Reg(j).String()) } } diff --git a/go.mod b/go.mod index 28d83dd92..c6886d572 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module go.opentelemetry.io/ebpf-profiler go 1.23.6 require ( - github.com/aws/aws-sdk-go-v2 v1.36.5 - github.com/aws/aws-sdk-go-v2/config v1.29.17 - github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 + github.com/aws/aws-sdk-go-v2 v1.37.0 + github.com/aws/aws-sdk-go-v2/config v1.30.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.85.0 github.com/cespare/xxhash/v2 v2.3.0 github.com/cilium/ebpf v0.19.0 github.com/docker/go-connections v0.5.0 @@ -44,21 +44,21 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.17.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.26.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.35.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/containerd/containerd v1.7.18 // indirect github.com/containerd/log v0.1.0 // indirect @@ -123,10 +123,3 @@ require ( google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -retract ( - v0.0.202532 - v0.0.202531 - v0.0.202529 - v0.0.202527 -) diff --git a/go.sum b/go.sum index 6999c4b84..15f18f911 100644 --- a/go.sum +++ b/go.sum @@ -6,42 +6,42 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2 v1.37.0 h1:YtCOESR/pN4j5oA7cVHSfOwIcuh/KwHC4DOSXFbv5F0= +github.com/aws/aws-sdk-go-v2 v1.37.0/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0 h1:6GMWV6CNpA/6fbFHnoAjrv4+LGfyTqZz2LtCHnspgDg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.0/go.mod h1:/mXlTIVG9jbxkqDnr5UQNQxW1HRYxeGklkM9vAFeabg= +github.com/aws/aws-sdk-go-v2/config v1.30.0 h1:XhzXYU2x/T441/0CBh0g6UUC/OFGk+FRpl3ThI8AqM8= +github.com/aws/aws-sdk-go-v2/config v1.30.0/go.mod h1:4j78A2ko2xc7SMLjjSUrgpp42vyneH9c8j3emf/CLTo= +github.com/aws/aws-sdk-go-v2/credentials v1.18.0 h1:r9W/BX4B1dEbsd2NogyuFXmEfYhdUULUVEOh0SDAovw= +github.com/aws/aws-sdk-go-v2/credentials v1.18.0/go.mod h1:SMtUJQRWEpyfC+ouDJNYdI7NNMqUjHM/Oaf0FV+vWNs= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.17.0 h1:ouCRc4lCriJtCnrIN4Kw2tA/uETRZBrxwb/607gRvkE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.17.0/go.mod h1:LW9/PxQD1SYFC7pnWcgqPhoyZprhjEdg5hBK6qYPLW8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0 h1:H2iZoqW/v2Jnrh1FnU725Bq6KJ0k2uP63yH+DcY+HUI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.0/go.mod h1:L0FqLbwMXHvNC/7crWV1iIxUlOKYZUE8KuTIA+TozAI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0 h1:EDped/rNzAhFPhVY0sDGbtD16OKqksfA8OjF/kLEgw8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.0/go.mod h1:uUI335jvzpZRPpjYx6ODc/wg1qH+NnoSTK/FwVeK0C0= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= -github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.0 h1:iLvW/zOkHGU3BDU5thWnj+UZ9pjhuVhv1loLj7yVtBw= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.0/go.mod h1:Fn3gvhdF1x5Rs9nUoCy/fJT1ms8f8dO7RqM9lJHuazQ= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.0 h1:qGyLBQPphYzUf+IIlb5tHnvg1U2Vc5hXPcP7oRSQfy0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.0/go.mod h1:g+dzKSLXiR/8ATkPXmLhPOI6rDdjLP3tngeo3FvDcIw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0 h1:eRhU3Sh8dGbaniI6B+I48XJMrTPRkK4DKo+vqIxziOU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.0/go.mod h1:paNLV18DZ6FnWE/bd06RIKPDIFpjuvCkGKWTG/GDBeM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.0 h1:6jusT+XCcvnD+Elxvm7bUf5sCMTpZEp3AKjYQ4tWJSo= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.0/go.mod h1:LimGpdIF/sTBdgqwOEkrArXLCoTamK/9L9x8IKBFTIc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.85.0 h1:gAV4NEp4A+JOrIdoXkAeyy6IOo7+X2s/jRuaHKYiMaU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.85.0/go.mod h1:JIQwK8sZ5MuKGm5rrFwp9MHUcyYEsQNpVixuPDlnwaU= +github.com/aws/aws-sdk-go-v2/service/sso v1.26.0 h1:cuFWHH87GP1NBGXXfMicUbE7Oty5KpPxN6w4JpmuxYc= +github.com/aws/aws-sdk-go-v2/service/sso v1.26.0/go.mod h1:aJBemdlbCKyOXEXdXBqS7E+8S9XTDcOTaoOjtng54hA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.0 h1:t2va+wewPOYIqC6XyJ4MGjiGKkczMAPsgq5W4FtL9ME= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.0/go.mod h1:ExCTcqYqN0hYYRsDlBVU8+68grqlWdgX9/nZJwQW4aY= +github.com/aws/aws-sdk-go-v2/service/sts v1.35.0 h1:FD9agdG4CeOGS3ORLByJk56YIXDS7mxFpmZyCtpqExc= +github.com/aws/aws-sdk-go-v2/service/sts v1.35.0/go.mod h1:NDzDPbBF1xtSTZUMuZx0w3hIfWzcL7X2AQ0Tr9becIQ= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -285,8 +285,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/exp v0.0.0-20250717185816-542afb5b7346 h1:vuCObX8mQzik1tfEcYxWZBuVsmQtD1IjxCyPKM18Bh4= golang.org/x/exp v0.0.0-20250717185816-542afb5b7346/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -347,8 +345,6 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1: google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.74.0 h1:sxRSkyLxlceWQiqDofxDot3d4u7DyoHPc7SBXMj8gGY= -google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= google.golang.org/grpc v1.74.1 h1:1liE5AupsvQAxKhrVPU9yhMEnyjmMi+F6FUmP9EB2ts= google.golang.org/grpc v1.74.1/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= diff --git a/internal/controller/controller.go b/internal/controller/controller.go index f9eeac858..3e5a8a429 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -195,10 +195,7 @@ func traceCacheSize(monitorInterval time.Duration, samplesPerSecond int, maxElements := maxElementsPerInterval(monitorInterval, samplesPerSecond, presentCPUCores) - size := maxElements * uint32(traceCacheIntervals) - if size < traceCacheMinSize { - size = traceCacheMinSize - } + size := max(maxElements*uint32(traceCacheIntervals), traceCacheMinSize) return util.NextPowerOfTwo(size) } diff --git a/interpreter/apmint/socket.go b/interpreter/apmint/socket.go index 0bd26391b..6172c4370 100644 --- a/interpreter/apmint/socket.go +++ b/interpreter/apmint/socket.go @@ -13,6 +13,7 @@ import ( "os" "path" "path/filepath" + "slices" "strconv" "strings" "syscall" @@ -40,10 +41,8 @@ type apmAgentSocket struct { func openAPMAgentSocket(pid libpf.PID, socketPath string) (*apmAgentSocket, error) { // Ensure that the socket path can't escape our root. socketPath = filepath.Clean(socketPath) - for _, segment := range strings.Split(socketPath, "/") { - if segment == ".." { - return nil, errors.New("socket path escapes root") - } + if slices.Contains(strings.Split(socketPath, "/"), "..") { + return nil, errors.New("socket path escapes root") } // Prepend root system to ensure that this also works with containerized apps. diff --git a/interpreter/dotnet/instance.go b/interpreter/dotnet/instance.go index 60ac70aa5..57ce777db 100644 --- a/interpreter/dotnet/instance.go +++ b/interpreter/dotnet/instance.go @@ -231,7 +231,7 @@ func (i *dotnetInstance) walkRangeList(ebpf interpreter.EbpfHandler, pid libpf.P stubName, blockNum, err) return } - for index := uint(0); index < numRangesInBlock; index++ { + for index := range uint(numRangesInBlock) { startAddr := npsr.Ptr(block, index*rangeSize) endAddr := npsr.Ptr(block, index*rangeSize+8) id := npsr.Ptr(block, index*rangeSize+16) diff --git a/interpreter/dotnet/method.go b/interpreter/dotnet/method.go index 2741aebee..408138310 100644 --- a/interpreter/dotnet/method.go +++ b/interpreter/dotnet/method.go @@ -66,7 +66,7 @@ func (m *dotnetMethod) mapPCOffsetToILOffset(pcOffset uint32, findCall bool) uin nativeOffset := uint32(0) ilOffset := uint32(0) lastCallILOffset := uint32(0) - for i := uint32(0); i < numEntries; i++ { + for i := range numEntries { nativeOffset += nr.Uint32() if findCall && nativeOffset >= pcOffset { // If finding call site, always return lastCallILOffset. @@ -109,7 +109,7 @@ func (m *dotnetMethod) dumpBounds() { // Decode Bounds Info portion of DebugInfo // https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/debuginfostore.cpp#L289-L310 nativeOffset := uint32(0) - for i := uint32(0); i < numEntries; i++ { + for i := range numEntries { nativeOffset += nr.Uint32() ilOffset := uint32(int32(nr.Uint32()) + mappingTypeMaxValue) sourceFlags := nr.Uint32() @@ -130,7 +130,7 @@ func dumpRichDebugInfo(richInfo []byte) { // Decode Rich Debug info's Inline Tree Nodes // https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/debuginfostore.cpp#L404-L429 var ilOffset, child, sibling int32 - for i := uint32(0); i < numInlineTree; i++ { + for range numInlineTree { ptr := nr.Ptr() ilOffset += nr.Int32() child += nr.Int32() @@ -144,7 +144,7 @@ func dumpRichDebugInfo(richInfo []byte) { nativeOffset := uint32(0) ilOffset = 0 inlinee := int32(0) - for i := uint32(0); i < numRichOffsets; i++ { + for range numRichOffsets { nativeOffset += nr.Uint32() inlinee += nr.Int32() ilOffset += nr.Int32() diff --git a/interpreter/dotnet/nibblereader.go b/interpreter/dotnet/nibblereader.go index aa2e846b0..9a9079c80 100644 --- a/interpreter/dotnet/nibblereader.go +++ b/interpreter/dotnet/nibblereader.go @@ -54,7 +54,7 @@ func (nr *nibbleReader) ReadNibble() uint8 { // https://github.com/dotnet/runtime/blob/v7.0.15/src/coreclr/inc/nibblestream.h#L250 func (nr *nibbleReader) Uint32() uint32 { val := uint32(0) - for i := 0; i < 11; i++ { + for range 11 { n := nr.ReadNibble() val = (val << 3) + uint32(n&0x7) if n&0x8 == 0 { diff --git a/interpreter/dotnet/pe.go b/interpreter/dotnet/pe.go index 4ac3405c8..6ebc5e531 100644 --- a/interpreter/dotnet/pe.go +++ b/interpreter/dotnet/pe.go @@ -835,7 +835,7 @@ func (pp *peParser) parseTables() error { if err := binary.Read(r, binary.LittleEndian, &tablesHeader); err != nil { return err } - for i := 0; i < 64; i++ { + for i := range 64 { if tablesHeader.Valid&(1< length { - bufSz = length - } + bufSz := min(uint32(16*1024), length) buf := make([]byte, bufSz) for offs := uint32(0); offs < length; offs += bufSz { if length-offs < bufSz { @@ -1054,7 +1051,7 @@ func (i *v8Instance) getSource(addr libpf.Address) *v8Source { log.Debugf("Reading LineEnds: %d: %v", len(data), err) if err == nil { lines := make([]uint32, len(data)/8) - for i := 0; i < len(lines); i++ { + for i := range lines { val := npsr.Uint64(data, uint(i*8)) lines[i] = decodeSMI(val) } diff --git a/interpreter/perl/data.go b/interpreter/perl/data.go index af30cc882..e5311a8f8 100644 --- a/interpreter/perl/data.go +++ b/interpreter/perl/data.go @@ -209,11 +209,7 @@ func newData(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo, return nil, fmt.Errorf("perl %x: PL_curstackinfo not found: %v", version, err) } stateInTSD = false - if curcopAddr < cursiAddr { - stateAddr = curcopAddr - } else { - stateAddr = cursiAddr - } + stateAddr = min(curcopAddr, cursiAddr) } // Perl_runops_standard is the main loop since Perl 5.6.0 (1999) diff --git a/interpreter/perl/instance.go b/interpreter/perl/instance.go index 11cd6aa3f..fc7ef1f21 100644 --- a/interpreter/perl/instance.go +++ b/interpreter/perl/instance.go @@ -239,7 +239,7 @@ func (i *perlInstance) getHEK(addr libpf.Address) (string, error) { defer func() { // Reset memory and return it for reuse. - for j := uint32(0); j < hekLen; j++ { + for j := range hekLen { (*syncPoolData)[j] = 0x0 } i.memPool.Put(syncPoolData) diff --git a/interpreter/perl/perl.go b/interpreter/perl/perl.go index 7228aa25b..49b77c3de 100644 --- a/interpreter/perl/perl.go +++ b/interpreter/perl/perl.go @@ -48,6 +48,7 @@ package perl // import "go.opentelemetry.io/ebpf-profiler/interpreter/perl" import ( "debug/elf" "regexp" + "slices" "go.opentelemetry.io/ebpf-profiler/interpreter" ) @@ -97,12 +98,10 @@ func Loader(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interpr if err != nil { return nil, err } - for _, n := range needed { - if libperlRegex.MatchString(n) { - // 'perl' linked with 'libperl'. The beef is in the library, - // so do not try to inspect the shim main binary. - return nil, nil - } + if slices.ContainsFunc(needed, libperlRegex.MatchString) { + // 'perl' linked with 'libperl'. The beef is in the library, + // so do not try to inspect the shim main binary. + return nil, nil } } diff --git a/interpreter/php/php_test.go b/interpreter/php/php_test.go index 5574a4072..2bff6387e 100644 --- a/interpreter/php/php_test.go +++ b/interpreter/php/php_test.go @@ -47,8 +47,6 @@ func TestVersionExtract(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { v, err := versionExtract(test.given) assert.Equal(t, test.expected, v) diff --git a/interpreter/python/python.go b/interpreter/python/python.go index 3b2cace3f..2accaf15f 100644 --- a/interpreter/python/python.go +++ b/interpreter/python/python.go @@ -13,6 +13,7 @@ import ( "io" "reflect" "regexp" + "slices" "strconv" "strings" "sync/atomic" @@ -606,10 +607,8 @@ func fieldByPythonName(obj reflect.Value, fieldName string) reflect.Value { for i := 0; i < obj.NumField(); i++ { objField := objType.Field(i) if nameTag, ok := objField.Tag.Lookup("name"); ok { - for _, pythonName := range strings.Split(nameTag, ",") { - if fieldName == pythonName { - return obj.Field(i) - } + if slices.Contains(strings.Split(nameTag, ","), fieldName) { + return obj.Field(i) } } if fieldName == objField.Name { @@ -711,12 +710,10 @@ func Loader(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interpr if err != nil { return nil, err } - for _, n := range needed { - if libpythonRegex.MatchString(n) { - // 'python' linked with 'libpython'. The beef is in the library, - // so do not try to inspect the shim main binary. - return nil, nil - } + if slices.ContainsFunc(needed, libpythonRegex.MatchString) { + // 'python' linked with 'libpython'. The beef is in the library, + // so do not try to inspect the shim main binary. + return nil, nil } } diff --git a/interpreter/python/python_test.go b/interpreter/python/python_test.go index 6e05c1f8a..d4d76c0d7 100644 --- a/interpreter/python/python_test.go +++ b/interpreter/python/python_test.go @@ -39,8 +39,6 @@ func TestFrozenNameToFileName(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { out, err := frozenNameToFileName(testcase.frozen) diff --git a/kallsyms/kallsyms.go b/kallsyms/kallsyms.go index 943fb2f78..b53a77369 100644 --- a/kallsyms/kallsyms.go +++ b/kallsyms/kallsyms.go @@ -95,12 +95,9 @@ func NewSymbolizer() (*Symbolizer, error) { // an index suitable for storing in the `symbol` struct. func (m *Module) addName(name string) uint32 { index := len(m.names) - l := len(name) // Cap the length to 255 bytes so it fits a byte. Longest seen // symbol so far is 83 bytes. - if l > 255 { - l = 255 - } + l := min(len(name), 255) m.names = append(m.names, byte(l)) m.names = append(m.names, unsafe.Slice(unsafe.StringData(name), l)...) return uint32(index) diff --git a/libpf/basehash/hash128_test.go b/libpf/basehash/hash128_test.go index aa3b05c45..69c0020e2 100644 --- a/libpf/basehash/hash128_test.go +++ b/libpf/basehash/hash128_test.go @@ -146,8 +146,6 @@ func TestHash128Format(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { output := fmt.Sprintf(test.formatter, h) assert.Equal(t, test.expected, output) @@ -175,8 +173,6 @@ func TestNew128FromString(t *testing.T) { } for name, tc := range tests { - name := name - tc := tc t.Run(name, func(t *testing.T) { got, err := New128FromString(tc.stringRepresentation) require.ErrorIs(t, err, tc.err) diff --git a/libpf/convenience_test.go b/libpf/convenience_test.go index cf187a8e6..94da86ee7 100644 --- a/libpf/convenience_test.go +++ b/libpf/convenience_test.go @@ -33,8 +33,6 @@ func TestIsValidString(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { assert.Equal(t, testcase.expected, util.IsValidString(string(testcase.input))) }) diff --git a/libpf/fileid_test.go b/libpf/fileid_test.go index 4d2e66836..44dc26be3 100644 --- a/libpf/fileid_test.go +++ b/libpf/fileid_test.go @@ -127,8 +127,6 @@ func TestFileIDFromExecutableReader(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { fileID, err := FileIDFromExecutableReader(bytes.NewReader(testcase.data)) require.NoError(t, err, "Failed to calculate executable ID") diff --git a/libpf/frameid_test.go b/libpf/frameid_test.go index 0bdc5952c..d1f7587e3 100644 --- a/libpf/frameid_test.go +++ b/libpf/frameid_test.go @@ -38,7 +38,6 @@ func TestFrameID(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.name, func(t *testing.T) { frameID, err := NewFrameIDFromString(test.input) assert.Equal(t, test.err, err) diff --git a/libpf/hash/hash_test.go b/libpf/hash/hash_test.go index e72f4087f..567d810c6 100644 --- a/libpf/hash/hash_test.go +++ b/libpf/hash/hash_test.go @@ -23,8 +23,6 @@ func TestUint64(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { result := Uint64(testcase.input) assert.Equal(t, testcase.expect, result) @@ -44,8 +42,6 @@ func TestUint32(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { result := Uint32(testcase.input) assert.Equal(t, testcase.expect, result) diff --git a/libpf/pfelf/pfelf_test.go b/libpf/pfelf/pfelf_test.go index 1e9addc57..cb78aa78c 100644 --- a/libpf/pfelf/pfelf_test.go +++ b/libpf/pfelf/pfelf_test.go @@ -135,7 +135,6 @@ func TestGetBuildIDFromNotesFile(t *testing.T) { func TestGetKernelVersionBytes(t *testing.T) { files := []string{"testdata/kernel-image", "testdata/ubuntu-kernel-image"} for _, f := range files { - f := f t.Run(f, func(t *testing.T) { elfFile := getELF(f, t) defer elfFile.Close() diff --git a/libpf/readatbuf/readatbuf_test.go b/libpf/readatbuf/readatbuf_test.go index ac0d219f6..9f503bcf9 100644 --- a/libpf/readatbuf/readatbuf_test.go +++ b/libpf/readatbuf/readatbuf_test.go @@ -32,7 +32,7 @@ func TestOutOfBoundsTail(t *testing.T) { r, err := readatbuf.New(buf, 5, 10) require.NoError(t, err) b := make([]byte, 1) - for i := int64(0); i < 32; i++ { + for i := range int64(32) { _, err = r.ReadAt(b, i) if i > 7 { require.ErrorIs(t, err, io.EOF) diff --git a/libpf/xsync/once_test.go b/libpf/xsync/once_test.go index 16ebb03d1..833a3a151 100644 --- a/libpf/xsync/once_test.go +++ b/libpf/xsync/once_test.go @@ -25,7 +25,7 @@ func TestOnceLock(t *testing.T) { assert.Nil(t, once.Get()) - for i := 0; i < 32; i++ { + for range 32 { wg.Add(1) go func() { diff --git a/lpm/lpm_test.go b/lpm/lpm_test.go index 546823a91..4d0bac609 100644 --- a/lpm/lpm_test.go +++ b/lpm/lpm_test.go @@ -25,8 +25,6 @@ func TestGetRightmostSetBit(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { output := getRightmostSetBit(test.input) assert.Equal(t, test.expected, output) @@ -57,8 +55,6 @@ func TestCalculatePrefixList(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { prefixes, err := CalculatePrefixList(test.start, test.end) if test.err { diff --git a/maccess/maccess_amd64_test.go b/maccess/maccess_amd64_test.go index 03b36ccff..2241fbd62 100644 --- a/maccess/maccess_amd64_test.go +++ b/maccess/maccess_amd64_test.go @@ -105,8 +105,6 @@ var codeblobs = map[string]struct { func TestGetJumpInCopyFromUserNoFault(t *testing.T) { for name, test := range codeblobs { - name := name - test := test t.Run(name, func(t *testing.T) { isPatched, err := CopyFromUserNoFaultIsPatched(test.code, test.copyFromUserNofaultAddr, test.nmiUaccessOkayAddr) diff --git a/main.go b/main.go index 089d4d3ba..995dea415 100644 --- a/main.go +++ b/main.go @@ -140,7 +140,7 @@ func mainWithExitCode() exitCode { return exitSuccess } -func failure(msg string, args ...interface{}) exitCode { +func failure(msg string, args ...any) exitCode { log.Errorf(msg, args...) return exitFailure } diff --git a/nativeunwind/elfunwindinfo/elfehframe.go b/nativeunwind/elfunwindinfo/elfehframe.go index c5378aea4..a37a8f9e2 100644 --- a/nativeunwind/elfunwindinfo/elfehframe.go +++ b/nativeunwind/elfunwindinfo/elfehframe.go @@ -588,7 +588,7 @@ func matchExpression(expr []dwarfExpression, template []expressionOpcode) bool { if len(expr) != len(template) { return false } - for i := 0; i < len(expr); i++ { + for i := range expr { if expr[i].opcode != template[i] { return false } diff --git a/nativeunwind/elfunwindinfo/elfehframe_test.go b/nativeunwind/elfunwindinfo/elfehframe_test.go index 2335e3f37..224053ed6 100644 --- a/nativeunwind/elfunwindinfo/elfehframe_test.go +++ b/nativeunwind/elfunwindinfo/elfehframe_test.go @@ -105,8 +105,6 @@ func TestEhFrame(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { ef, err := pfelf.Open(test.elfFile) require.NoError(t, err) @@ -167,8 +165,6 @@ func TestParseCIE(t *testing.T) { } for name, tc := range tests { - name := name - tc := tc t.Run(name, func(t *testing.T) { fakeReader := &reader{ debugFrame: tc.debugFrame, diff --git a/nativeunwind/elfunwindinfo/elfgopclntab_test.go b/nativeunwind/elfunwindinfo/elfgopclntab_test.go index 84b372528..679fc1186 100644 --- a/nativeunwind/elfunwindinfo/elfgopclntab_test.go +++ b/nativeunwind/elfunwindinfo/elfgopclntab_test.go @@ -81,8 +81,6 @@ func TestParseGoPclntab(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { ef, err := pfelf.Open(test.elfFile) require.NoError(t, err) diff --git a/nativeunwind/elfunwindinfo/stackdeltaextraction_test.go b/nativeunwind/elfunwindinfo/stackdeltaextraction_test.go index 961f67833..8f82ff34a 100644 --- a/nativeunwind/elfunwindinfo/stackdeltaextraction_test.go +++ b/nativeunwind/elfunwindinfo/stackdeltaextraction_test.go @@ -291,8 +291,6 @@ func TestEntryDetection(t *testing.T) { } for name, test := range testCases { - name := name - test := test t.Run(name, func(t *testing.T) { entryLen := detectEntryCode(test.machine, test.code) assert.Equal(t, test.len, entryLen) diff --git a/periodiccaller/periodiccaller_test.go b/periodiccaller/periodiccaller_test.go index a3abb2241..4af053bc9 100644 --- a/periodiccaller/periodiccaller_test.go +++ b/periodiccaller/periodiccaller_test.go @@ -238,7 +238,7 @@ func TestPeriodicCallerManualTrigger(t *testing.T) { }) defer stop() - for i := 0; i < numTrigger; i++ { + for range numTrigger { trigger <- true } <-done diff --git a/processmanager/ebpf/asyncupdate.go b/processmanager/ebpf/asyncupdate.go index da7c91f4a..37ef923d9 100644 --- a/processmanager/ebpf/asyncupdate.go +++ b/processmanager/ebpf/asyncupdate.go @@ -48,7 +48,7 @@ type asyncMapUpdaterPool struct { func newAsyncMapUpdaterPool(ctx context.Context, numWorkers, workerQueueCapacity int) *asyncMapUpdaterPool { pool := &asyncMapUpdaterPool{} - for i := 0; i < numWorkers; i++ { + for range numWorkers { queue := make(chan asyncMapInMapUpdate, workerQueueCapacity) worker := &asyncUpdateWorker{ctx: ctx, queue: queue} go worker.serve() diff --git a/processmanager/ebpf/ebpf.go b/processmanager/ebpf/ebpf.go index c32b07e9c..4d5526f2f 100644 --- a/processmanager/ebpf/ebpf.go +++ b/processmanager/ebpf/ebpf.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "math/bits" + "reflect" "sync" "unsafe" @@ -85,26 +86,25 @@ type EbpfHandler interface { type ebpfMapsImpl struct { // Interpreter related eBPF maps - interpreterOffsets *cebpf.Map - dotnetProcs *cebpf.Map - perlProcs *cebpf.Map - pyProcs *cebpf.Map - hotspotProcs *cebpf.Map - phpProcs *cebpf.Map - rubyProcs *cebpf.Map - v8Procs *cebpf.Map - apmIntProcs *cebpf.Map - goProcs *cebpf.Map - goLabelsProcs *cebpf.Map - clProcs *cebpf.Map - luajitProcs *cebpf.Map + InterpreterOffsets *cebpf.Map `name:"interpreter_offsets"` + DotnetProcs *cebpf.Map `name:"dotnet_procs"` + PerlProcs *cebpf.Map `name:"perl_procs"` + PyProcs *cebpf.Map `name:"py_procs"` + HotspotProcs *cebpf.Map `name:"hotspot_procs"` + PhpProcs *cebpf.Map `name:"php_procs"` + RubyProcs *cebpf.Map `name:"ruby_procs"` + V8Procs *cebpf.Map `name:"v8_procs"` + ApmIntProcs *cebpf.Map `name:"apm_int_procs"` + GoLabelsProcs *cebpf.Map `name:"go_labels_procs"` + ClProcs *cebpf.Map `name:"cl_procs"` + LuajitProcs *cebpf.Map `name:"luajit_procs"` // Stackdelta and process related eBPF maps - exeIDToStackDeltaMaps []*cebpf.Map - stackDeltaPageToInfo *cebpf.Map - pidPageToMappingInfo *cebpf.Map - unwindInfoArray *cebpf.Map - reportedPIDs *cebpf.Map + ExeIDToStackDeltaMaps []*cebpf.Map + StackDeltaPageToInfo *cebpf.Map `name:"stack_delta_page_to_info"` + PidPageToMappingInfo *cebpf.Map `name:"pid_page_to_mapping_info"` + UnwindInfoArray *cebpf.Map `name:"unwind_info_array"` + ReportedPIDs *cebpf.Map `name:"reported_pids"` errCounterLock sync.Mutex errCounter map[metrics.MetricID]int64 @@ -115,25 +115,6 @@ type ebpfMapsImpl struct { updateWorkers *asyncMapUpdaterPool } -var outerMapsName = [...]string{ - "exe_id_to_8_stack_deltas", - "exe_id_to_9_stack_deltas", - "exe_id_to_10_stack_deltas", - "exe_id_to_11_stack_deltas", - "exe_id_to_12_stack_deltas", - "exe_id_to_13_stack_deltas", - "exe_id_to_14_stack_deltas", - "exe_id_to_15_stack_deltas", - "exe_id_to_16_stack_deltas", - "exe_id_to_17_stack_deltas", - "exe_id_to_18_stack_deltas", - "exe_id_to_19_stack_deltas", - "exe_id_to_20_stack_deltas", - "exe_id_to_21_stack_deltas", - "exe_id_to_22_stack_deltas", - "exe_id_to_23_stack_deltas", -} - // Compile time check to make sure ebpfMapsImpl satisfies the interface . var _ EbpfHandler = &ebpfMapsImpl{} @@ -146,112 +127,30 @@ func LoadMaps(ctx context.Context, maps map[string]*cebpf.Map) (EbpfHandler, err impl := &ebpfMapsImpl{} impl.errCounter = make(map[metrics.MetricID]int64) - interpreterOffsets, ok := maps["interpreter_offsets"] - if !ok { - log.Fatalf("Map interpreter_offsets is not available") - } - impl.interpreterOffsets = interpreterOffsets - - dotnetProcs, ok := maps["dotnet_procs"] - if !ok { - log.Fatalf("Map dotnet_procs is not available") - } - impl.dotnetProcs = dotnetProcs - - perlProcs, ok := maps["perl_procs"] - if !ok { - log.Fatalf("Map perl_procs is not available") - } - impl.perlProcs = perlProcs - - pyProcs, ok := maps["py_procs"] - if !ok { - log.Fatalf("Map py_procs is not available") - } - impl.pyProcs = pyProcs - - hotspotProcs, ok := maps["hotspot_procs"] - if !ok { - log.Fatalf("Map hotspot_procs is not available") - } - impl.hotspotProcs = hotspotProcs - - phpProcs, ok := maps["php_procs"] - if !ok { - log.Fatalf("Map php_procs is not available") - } - impl.phpProcs = phpProcs - - rubyProcs, ok := maps["ruby_procs"] - if !ok { - log.Fatalf("Map ruby_procs is not available") - } - impl.rubyProcs = rubyProcs - - v8Procs, ok := maps["v8_procs"] - if !ok { - log.Fatalf("Map v8_procs is not available") - } - impl.v8Procs = v8Procs - - apmIntProcs, ok := maps["apm_int_procs"] - if !ok { - log.Fatalf("Map apm_int_procs is not available") - } - impl.apmIntProcs = apmIntProcs - - goProcs, ok := maps["go_procs"] - if !ok { - log.Fatalf("Map go_procs is not available") - } - impl.goProcs = goProcs - - goLabelsProcs, ok := maps["go_labels_procs"] - if !ok { - log.Fatalf("Map go_labels_procs is not available") - } - impl.goLabelsProcs = goLabelsProcs - - clProcs, ok := maps["cl_procs"] - if !ok { - log.Fatalf("Map cl_procs is not available") - } - impl.clProcs = clProcs - - luajitProcs, ok := maps["luajit_procs"] - if !ok { - log.Fatalf("Map luajit_procs is not available") - } - impl.luajitProcs = luajitProcs - - impl.stackDeltaPageToInfo, ok = maps["stack_delta_page_to_info"] - if !ok { - log.Fatalf("Map stack_delta_page_to_info is not available") - } - - impl.pidPageToMappingInfo, ok = maps["pid_page_to_mapping_info"] - if !ok { - log.Fatalf("Map pid_page_to_mapping_info is not available") - } - - impl.unwindInfoArray, ok = maps["unwind_info_array"] - if !ok { - log.Fatalf("Map unwind_info_array is not available") - } - - impl.reportedPIDs, ok = maps["reported_pids"] - if !ok { - log.Fatalf("Map reported_pids is not available") + implRefVal := reflect.ValueOf(impl).Elem() + implRefType := reflect.TypeOf(impl).Elem() + for i := 0; i < implRefType.NumField(); i++ { + fieldType := implRefType.Field(i) + nameTag, ok := fieldType.Tag.Lookup("name") + if !ok { + continue + } + mapVal, ok := maps[nameTag] + if !ok { + log.Fatalf("Map %v is not available", nameTag) + } + implRefVal.Field(i).Set(reflect.ValueOf(mapVal)) } - impl.exeIDToStackDeltaMaps = make([]*cebpf.Map, len(outerMapsName)) + numBuckets := support.StackDeltaBucketLargest - support.StackDeltaBucketSmallest + 1 + impl.ExeIDToStackDeltaMaps = make([]*cebpf.Map, numBuckets) for i := support.StackDeltaBucketSmallest; i <= support.StackDeltaBucketLargest; i++ { deltasMapName := fmt.Sprintf("exe_id_to_%d_stack_deltas", i) deltasMap, ok := maps[deltasMapName] if !ok { log.Fatalf("Map %s is not available", deltasMapName) } - impl.exeIDToStackDeltaMaps[i-support.StackDeltaBucketSmallest] = deltasMap + impl.ExeIDToStackDeltaMaps[i-support.StackDeltaBucketSmallest] = deltasMap } if err := probeBatchOperations(cebpf.Hash); err == nil { @@ -280,7 +179,7 @@ func (impl *ebpfMapsImpl) UpdateInterpreterOffsets(ebpfProgIndex uint16, fileID if err != nil { return err } - if err := impl.interpreterOffsets.Update(unsafe.Pointer(&key), unsafe.Pointer(&value), + if err := impl.InterpreterOffsets.Update(unsafe.Pointer(&key), unsafe.Pointer(&value), cebpf.UpdateAny); err != nil { log.Fatalf("Failed to place interpreter range in map: %v", err) } @@ -322,29 +221,27 @@ func InterpreterOffsetKeyValue(ebpfProgIndex uint16, fileID host.FileID, func (impl *ebpfMapsImpl) getInterpreterTypeMap(typ libpf.InterpreterType) (*cebpf.Map, error) { switch typ { case libpf.Dotnet: - return impl.dotnetProcs, nil + return impl.DotnetProcs, nil case libpf.Perl: - return impl.perlProcs, nil + return impl.PerlProcs, nil case libpf.Python: - return impl.pyProcs, nil + return impl.PyProcs, nil case libpf.HotSpot: - return impl.hotspotProcs, nil + return impl.HotspotProcs, nil case libpf.PHP: - return impl.phpProcs, nil + return impl.PhpProcs, nil case libpf.Ruby: - return impl.rubyProcs, nil + return impl.RubyProcs, nil case libpf.V8: - return impl.v8Procs, nil + return impl.V8Procs, nil case libpf.APMInt: - return impl.apmIntProcs, nil - case libpf.Go: - return impl.goProcs, nil + return impl.ApmIntProcs, nil case libpf.GoLabels: - return impl.goLabelsProcs, nil + return impl.GoLabelsProcs, nil case libpf.CustomLabels: - return impl.clProcs, nil + return impl.ClProcs, nil case libpf.LuaJIT: - return impl.luajitProcs, nil + return impl.LuajitProcs, nil default: return nil, fmt.Errorf("type %d is not (yet) supported", typ) } @@ -383,20 +280,27 @@ func (impl *ebpfMapsImpl) DeleteProcData(typ libpf.InterpreterType, pid libpf.PI return nil } +// getPIDPage initializes a PIDPage instance. +func getPIDPage(pid libpf.PID, key uint64, length uint32) support.PIDPage { + // pid_page_to_mapping_info is an LPM trie and expects the pid and page + // to be in big endian format. + return support.PIDPage{ + Pid: bits.ReverseBytes32(uint32(pid)), + Page: bits.ReverseBytes64(key), + PrefixLen: support.BitWidthPID + length, + } +} + +// getPIDPageFromPrefix initializes a PIDPage instance from a PID and lpm.Prefix. +func getPIDPageFromPrefix(pid libpf.PID, prefix lpm.Prefix) support.PIDPage { + return getPIDPage(pid, prefix.Key, prefix.Length) +} + // UpdatePidInterpreterMapping updates the eBPF map pidPageToMappingInfo with the // data required to call the correct interpreter unwinder for that memory region. func (impl *ebpfMapsImpl) UpdatePidInterpreterMapping(pid libpf.PID, prefix lpm.Prefix, interpreterProgram uint8, fileID host.FileID, bias uint64) error { - // pidPageToMappingInfo is a LPM trie and expects the pid and page - // to be in big endian format. - bePid := bits.ReverseBytes32(uint32(pid)) - bePage := bits.ReverseBytes64(prefix.Key) - - cKey := support.PIDPage{ - PrefixLen: support.BitWidthPID + prefix.Length, - Pid: bePid, - Page: bePage, - } + cKey := getPIDPageFromPrefix(pid, prefix) biasAndUnwindProgram, err := support.EncodeBiasAndUnwindProgram(bias, interpreterProgram) if err != nil { return err @@ -407,7 +311,7 @@ func (impl *ebpfMapsImpl) UpdatePidInterpreterMapping(pid libpf.PID, prefix lpm. Bias_and_unwind_program: biasAndUnwindProgram, } - return impl.pidPageToMappingInfo.Update(unsafe.Pointer(&cKey), unsafe.Pointer(&cValue), + return impl.PidPageToMappingInfo.Update(unsafe.Pointer(&cKey), unsafe.Pointer(&cValue), cebpf.UpdateNoExist) } @@ -416,17 +320,8 @@ func (impl *ebpfMapsImpl) UpdatePidInterpreterMapping(pid libpf.PID, prefix lpm. // interpreter process dies or a region that formerly required interpreter-based unwinding is no // longer needed. func (impl *ebpfMapsImpl) DeletePidInterpreterMapping(pid libpf.PID, prefix lpm.Prefix) error { - // pidPageToMappingInfo is a LPM trie and expects the pid and page - // to be in big endian format. - bePid := bits.ReverseBytes32(uint32(pid)) - bePage := bits.ReverseBytes64(prefix.Key) - - cKey := support.PIDPage{ - PrefixLen: support.BitWidthPID + prefix.Length, - Pid: bePid, - Page: bePage, - } - return impl.pidPageToMappingInfo.Delete(unsafe.Pointer(&cKey)) + cKey := getPIDPageFromPrefix(pid, prefix) + return impl.PidPageToMappingInfo.Delete(unsafe.Pointer(&cKey)) } // trackMapError is a wrapper to report issues with changes to eBPF maps. @@ -458,7 +353,7 @@ func (impl *ebpfMapsImpl) CollectMetrics() []metrics.Metric { return counts } -// poolPIDPage caches reusable heap-allocated support.PIDPage instances +// poolPIDPage caches reusable heap-allocated PIDPage instances // to avoid excessive heap allocations. var poolPIDPage = sync.Pool{ New: func() any { @@ -466,22 +361,11 @@ var poolPIDPage = sync.Pool{ }, } -// getPIDPage initializes a support.PIDPage instance. -func getPIDPage(pid libpf.PID, prefix lpm.Prefix) support.PIDPage { - // pid_page_to_mapping_info is an LPM trie and expects the pid and page - // to be in big endian format. - return support.PIDPage{ - Pid: bits.ReverseBytes32(uint32(pid)), - Page: bits.ReverseBytes64(prefix.Key), - PrefixLen: support.BitWidthPID + prefix.Length, - } -} - -// getPIDPagePooled returns a heap-allocated and initialized support.PIDPage instance. +// getPIDPagePooled returns a heap-allocated and initialized PIDPage instance. // After usage, put the instance back into the pool with poolPIDPage.Put(). func getPIDPagePooled(pid libpf.PID, prefix lpm.Prefix) *support.PIDPage { cPIDPage := poolPIDPage.Get().(*support.PIDPage) - *cPIDPage = getPIDPage(pid, prefix) + *cPIDPage = getPIDPageFromPrefix(pid, prefix) return cPIDPage } @@ -586,21 +470,21 @@ func (impl *ebpfMapsImpl) getOuterMap(mapID uint16) *cebpf.Map { mapID > support.StackDeltaBucketLargest { return nil } - return impl.exeIDToStackDeltaMaps[mapID-support.StackDeltaBucketSmallest] + return impl.ExeIDToStackDeltaMaps[mapID-support.StackDeltaBucketSmallest] } // RemoveReportedPID removes a PID from the reported_pids eBPF map. The kernel component will // place a PID in this map before it reports it to Go for further processing. func (impl *ebpfMapsImpl) RemoveReportedPID(pid libpf.PID) { key := uint32(pid) - _ = impl.reportedPIDs.Delete(unsafe.Pointer(&key)) + _ = impl.ReportedPIDs.Delete(unsafe.Pointer(&key)) } // UpdateUnwindInfo writes UnwindInfo into the unwind info array at the given index func (impl *ebpfMapsImpl) UpdateUnwindInfo(index uint16, info sdtypes.UnwindInfo) error { - if uint32(index) >= impl.unwindInfoArray.MaxEntries() { + if uint32(index) >= impl.UnwindInfoArray.MaxEntries() { return fmt.Errorf("unwind info array full (%d/%d items)", - index, impl.unwindInfoArray.MaxEntries()) + index, impl.UnwindInfoArray.MaxEntries()) } key := uint32(index) @@ -612,7 +496,7 @@ func (impl *ebpfMapsImpl) UpdateUnwindInfo(index uint16, info sdtypes.UnwindInfo FpParam: info.FPParam, } return impl.trackMapError(metrics.IDUnwindInfoArrayUpdate, - impl.unwindInfoArray.Update(unsafe.Pointer(&key), unsafe.Pointer(&value), + impl.UnwindInfoArray.Update(unsafe.Pointer(&key), unsafe.Pointer(&value), cebpf.UpdateAny)) } @@ -739,7 +623,7 @@ func (impl *ebpfMapsImpl) UpdateStackDeltaPages(fileID host.FileID, numDeltasPer } if impl.hasGenericBatchOperations { - _, err := impl.stackDeltaPageToInfo.BatchUpdate( + _, err := impl.StackDeltaPageToInfo.BatchUpdate( ptrCastMarshaler[support.StackDeltaPageKey](keys), ptrCastMarshaler[support.StackDeltaPageInfo](values), &cebpf.BatchOptions{Flags: uint64(cebpf.UpdateNoExist)}) @@ -748,7 +632,7 @@ func (impl *ebpfMapsImpl) UpdateStackDeltaPages(fileID host.FileID, numDeltasPer for index := range keys { if err := impl.trackMapError(metrics.IDStackDeltaPageToInfoUpdate, - impl.stackDeltaPageToInfo.Update(unsafe.Pointer(&keys[index]), + impl.StackDeltaPageToInfo.Update(unsafe.Pointer(&keys[index]), unsafe.Pointer(&values[index]), cebpf.UpdateNoExist)); err != nil { return err } @@ -763,7 +647,7 @@ func (impl *ebpfMapsImpl) DeleteStackDeltaPage(fileID host.FileID, page uint64) Page: page, } return impl.trackMapError(metrics.IDStackDeltaPageToInfoDelete, - impl.stackDeltaPageToInfo.Delete(unsafe.Pointer(&key))) + impl.StackDeltaPageToInfo.Delete(unsafe.Pointer(&key))) } // UpdatePidPageMappingInfo adds the pid and page combination with a corresponding fileID and @@ -786,7 +670,7 @@ func (impl *ebpfMapsImpl) UpdatePidPageMappingInfo(pid libpf.PID, prefix lpm.Pre defer poolPIDPageMappingInfo.Put(cValue) return impl.trackMapError(metrics.IDPidPageToMappingInfoUpdate, - impl.pidPageToMappingInfo.Update(unsafe.Pointer(cKey), unsafe.Pointer(cValue), + impl.PidPageToMappingInfo.Update(unsafe.Pointer(cKey), unsafe.Pointer(cValue), cebpf.UpdateNoExist)) } @@ -813,8 +697,8 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfoSingle(pid libpf.PID, prefixes var deleted int var combinedErrors error for _, prefix := range prefixes { - *cKey = getPIDPage(pid, prefix) - if err := impl.pidPageToMappingInfo.Delete(unsafe.Pointer(cKey)); err != nil { + *cKey = getPIDPageFromPrefix(pid, prefix) + if err := impl.PidPageToMappingInfo.Delete(unsafe.Pointer(cKey)); err != nil { _ = impl.trackMapError(metrics.IDPidPageToMappingInfoDelete, err) combinedErrors = errors.Join(combinedErrors, err) continue @@ -829,10 +713,10 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfoBatch(pid libpf.PID, prefixes // Prepare all keys based on the given prefixes. cKeys := make([]support.PIDPage, 0, len(prefixes)) for _, prefix := range prefixes { - cKeys = append(cKeys, getPIDPage(pid, prefix)) + cKeys = append(cKeys, getPIDPageFromPrefix(pid, prefix)) } - deleted, err := impl.pidPageToMappingInfo.BatchDelete( + deleted, err := impl.PidPageToMappingInfo.BatchDelete( ptrCastMarshaler[support.PIDPage](cKeys), nil) return deleted, impl.trackMapError(metrics.IDPidPageToMappingInfoBatchDelete, err) } @@ -840,21 +724,11 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfoBatch(pid libpf.PID, prefixes // LookupPidPageInformation returns the fileID and bias for a given pid and page combination from // the eBPF map pid_page_to_mapping_info. // So far this function is used only in tests. -func (impl *ebpfMapsImpl) LookupPidPageInformation(pid uint32, page uint64) (host.FileID, +func (impl *ebpfMapsImpl) LookupPidPageInformation(pid libpf.PID, page uint64) (host.FileID, uint64, error) { - // pid_page_to_mapping_info is a LPM trie and expects the pid and page - // to be in big endian format. - bePid := bits.ReverseBytes32(pid) - bePage := bits.ReverseBytes64(page) - - cKey := support.PIDPage{ - PrefixLen: uint32(support.BitWidthPID + support.BitWidthPage), - Pid: bePid, - Page: bePage, - } + cKey := getPIDPage(pid, page, support.BitWidthPage) cValue := support.PIDPageMappingInfo{} - - if err := impl.pidPageToMappingInfo.Lookup(unsafe.Pointer(&cKey), + if err := impl.PidPageToMappingInfo.Lookup(unsafe.Pointer(&cKey), unsafe.Pointer(&cValue)); err != nil { return host.FileID(0), 0, fmt.Errorf("failed to lookup page 0x%x for PID %d: %v", page, pid, err) diff --git a/processmanager/ebpf/ebpf_integration_test.go b/processmanager/ebpf/ebpf_integration_test.go index c1af9a3c5..f4761edf5 100644 --- a/processmanager/ebpf/ebpf_integration_test.go +++ b/processmanager/ebpf/ebpf_integration_test.go @@ -33,7 +33,7 @@ func loadTracers(t *testing.T) *ebpfMapsImpl { require.NoError(t, err) return &ebpfMapsImpl{ - pidPageToMappingInfo: pidPageToMappingInfo, + PidPageToMappingInfo: pidPageToMappingInfo, } } @@ -63,7 +63,7 @@ func TestLPM(t *testing.T) { err := impl.UpdatePidPageMappingInfo(test.pid, prefix, test.fileID, test.bias) require.NoError(t, err) - fileID, bias, err := impl.LookupPidPageInformation(uint32(test.pid), test.rip) + fileID, bias, err := impl.LookupPidPageInformation(test.pid, test.rip) if assert.NoError(t, err) { assert.Equal(t, test.fileID, uint64(fileID)) assert.Equal(t, test.bias, bias) diff --git a/processmanager/ebpf/ebpf_test.go b/processmanager/ebpf/ebpf_test.go index fec5bf5dd..fb33e6022 100644 --- a/processmanager/ebpf/ebpf_test.go +++ b/processmanager/ebpf/ebpf_test.go @@ -27,8 +27,6 @@ func TestMapID(t *testing.T) { (1 << support.StackDeltaBucketLargest) - 1: support.StackDeltaBucketLargest, } for numStackDeltas, expectedShift := range testCases { - numStackDeltas := numStackDeltas - expectedShift := expectedShift t.Run(fmt.Sprintf("deltas %d", numStackDeltas), func(t *testing.T) { shift, err := getMapID(numStackDeltas) require.NoError(t, err) diff --git a/processmanager/manager.go b/processmanager/manager.go index 596b09c21..e5ff83a3f 100644 --- a/processmanager/manager.go +++ b/processmanager/manager.go @@ -56,6 +56,8 @@ var ( errUnknownMapping = errors.New("unknown memory mapping") // errUnknownPID indicates that the process is not known to the process manager. errUnknownPID = errors.New("unknown process") + // errPIDGone indicates that a process is no longer managed by the process manager. + errPIDGone = errors.New("interpreter process gone") ) // New creates a new ProcessManager which is responsible for keeping track of loading @@ -198,7 +200,7 @@ func (pm *ProcessManager) symbolizeFrame(frame int, trace *host.Trace, defer pm.mu.Unlock() if len(pm.interpreters[trace.PID]) == 0 { - return errors.New("interpreter process gone") + return errPIDGone } for _, instance := range pm.interpreters[trace.PID] { @@ -208,7 +210,7 @@ func (pm *ProcessManager) symbolizeFrame(frame int, trace *host.Trace, // So continue with the next interpreter instance for this PID. continue } - return fmt.Errorf("symbolization failed: %w", err) + return err } return nil } @@ -227,7 +229,7 @@ func (pm *ProcessManager) ConvertTrace(trace *host.Trace) (newTrace *libpf.Trace CustomLabels: trace.CustomLabels, } - for i := 0; i < traceLen; i++ { + for i := range traceLen { frame := &trace.Frames[i] if frame.Type.IsError() { diff --git a/processmanager/manager_test.go b/processmanager/manager_test.go index 514675f1f..52eaf8736 100644 --- a/processmanager/manager_test.go +++ b/processmanager/manager_test.go @@ -121,9 +121,9 @@ var _ nativeunwind.StackDeltaProvider = (*dummyStackDeltaProvider)(nil) // these files afterwards. func generateDummyFiles(t *testing.T, num int) []string { t.Helper() - var files []string + files := make([]string, 0, num) - for i := 0; i < num; i++ { + for i := range num { name := fmt.Sprintf("dummy%d", i) tmpfile, err := os.CreateTemp(t.TempDir(), "*"+name) require.NoError(t, err) @@ -305,8 +305,6 @@ func TestInterpreterConvertTrace(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { mapper := NewMapFileIDMapper() for i := range testcase.trace.Frames { @@ -394,7 +392,6 @@ func TestNewMapping(t *testing.T) { } for name, testcase := range tests { - testcase := testcase t.Run(name, func(t *testing.T) { // The generated dummy files do not contain valid stack deltas, // so we replace the stack delta provider. @@ -582,7 +579,6 @@ func TestProcExit(t *testing.T) { } for name, testcase := range tests { - testcase := testcase t.Run(name, func(t *testing.T) { // The generated dummy files do not contain valid stack deltas, // so we replace the stack delta provider. diff --git a/reporter/samples/attrmgr_test.go b/reporter/samples/attrmgr_test.go index 85e23338a..5b76ebb59 100644 --- a/reporter/samples/attrmgr_test.go +++ b/reporter/samples/attrmgr_test.go @@ -98,7 +98,6 @@ func TestAttrTableManager(t *testing.T) { } for name, tc := range tests { - name := name t.Run(name, func(t *testing.T) { attrTable := pprofile.NewAttributeTableSlice() mgr := NewAttrTableManager(attrTable) diff --git a/scripts/local-collector.sh b/scripts/local-collector.sh new file mode 100755 index 000000000..07b107e59 --- /dev/null +++ b/scripts/local-collector.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -euo pipefail + +# Check if COLLECTOR_PATH is set +if [ -z "${COLLECTOR_PATH:-}" ]; then + echo "Error: COLLECTOR_PATH is not set" + exit 1 +fi + +echo "Setting the local Collector to a local checkout at $COLLECTOR_PATH" + +# Replace collector module dependencies with local paths +go list -m -u all | grep 'go\.opentelemetry\.io/collector' | while read -r line; do + MODULE=$(echo "$line" | awk '{print $1}') + REL_PATH=${MODULE#go.opentelemetry.io/collector/} + LOCAL_PATH="$COLLECTOR_PATH/$REL_PATH" + echo "Replacing $MODULE => $LOCAL_PATH" + go mod edit -replace="$MODULE=$LOCAL_PATH" +done diff --git a/stringutil/stringutil_test.go b/stringutil/stringutil_test.go index 954c74897..eadb53d6e 100644 --- a/stringutil/stringutil_test.go +++ b/stringutil/stringutil_test.go @@ -29,8 +29,6 @@ func TestFieldsN(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { var fields [4]string n := FieldsN(testcase.input, fields[:testcase.maxFields]) @@ -58,8 +56,6 @@ func TestSplitN(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { var fields [4]string n := SplitN(testcase.input, "-", fields[:testcase.maxFields]) diff --git a/successfailurecounter/successfailurecounter_test.go b/successfailurecounter/successfailurecounter_test.go index 0fa4cd59b..f4a7decf8 100644 --- a/successfailurecounter/successfailurecounter_test.go +++ b/successfailurecounter/successfailurecounter_test.go @@ -72,8 +72,6 @@ func TestSuccessFailureCounter(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { var success, failure atomic.Uint64 sfc := New(&success, &failure) diff --git a/support/ebpf/Makefile b/support/ebpf/Makefile index 0acb416df..4aff96d7b 100644 --- a/support/ebpf/Makefile +++ b/support/ebpf/Makefile @@ -39,7 +39,6 @@ FLAGS=$(TARGET_FLAGS) -g \ -Wall -Wextra -Werror \ -Wno-address-of-packed-member \ -Wno-unused-label \ - -Wno-unused-parameter \ -Wno-sign-compare \ -fno-stack-protector \ -D__SOURCE_DATE_EPOCH__=0 \ @@ -48,6 +47,7 @@ FLAGS=$(TARGET_FLAGS) -g \ SRCS := $(wildcard *.ebpf.c) OBJS := $(SRCS:.c=.$(TARGET_ARCH).o) +DEPS := $(OBJS:.o=.d) .DEFAULT_GOAL := all @@ -62,10 +62,8 @@ arm64: errors.h: ../../tools/errors-codegen/errors.json go run ../../tools/errors-codegen/main.go bpf $@ -%.ebpf.c: errors.h ; - -%.ebpf.$(TARGET_ARCH).o: %.ebpf.c - $(BPF_CLANG) $(FLAGS) -o $@ +%.ebpf.$(TARGET_ARCH).o: %.ebpf.c errors.h + $(BPF_CLANG) $(FLAGS) -MMD -MP -o $@ $(TRACER_NAME): $(OBJS) $(BPF_LINK) $^ -o - | $(LLC) -march=bpf -mcpu=v2 -filetype=obj -o $@ @@ -82,10 +80,12 @@ bloatcheck: $(TRACER_NAME) python3 bloat-o-meter $(TRACER_NAME).baseline $(TRACER_NAME) lint: - $(CLANG_FORMAT) -Werror --dry-run -style=file *.[ch] + $(CLANG_FORMAT) -Werror --dry-run -style=file *.[ch] ../../tools/coredump/*.[ch] format: $(CLANG_FORMAT) -i -style=file *.[ch] clean: - rm -f *.o + rm -f *.o *.d + +-include $(DEPS) diff --git a/support/ebpf/bpfdefs.h b/support/ebpf/bpfdefs.h index f389f58a6..b0c405d52 100644 --- a/support/ebpf/bpfdefs.h +++ b/support/ebpf/bpfdefs.h @@ -7,6 +7,10 @@ // with_debug_output is declared in native_stack_trace.ebpf.c extern u32 with_debug_output; +// UNUSED is a macro that marks a parameter or variable as intentionally unused. +// It prevents compiler warnings about unused variables while keeping them in the code. +#define UNUSED __attribute__((unused)) + #if defined(TESTING_COREDUMP) // BPF_RODATA_VAR declares a global variable in the .rodata section, @@ -26,6 +30,9 @@ extern u32 with_debug_output; #define printt(fmt, ...) bpf_log(fmt, ##__VA_ARGS__) #define DEBUG_PRINT(fmt, ...) bpf_log(fmt, ##__VA_ARGS__) + // Macro for loop unrolling. Expands to nothing for TESTING_COREDUMP. + #define UNROLL + // BPF helpers. Mostly stubs to dispatch the call to Go code with the context ID. int bpf_tail_call(void *ctx, bpf_map_def *map, int index); unsigned long long bpf_ktime_get_ns(void); @@ -37,7 +44,7 @@ static inline long bpf_probe_read_user(void *buf, u32 sz, const void *ptr) return __bpf_probe_read_user(__cgo_ctx->id, buf, sz, ptr); } -static inline long bpf_probe_read_kernel(void *buf, u32 sz, const void *ptr) +static inline long bpf_probe_read_kernel(UNUSED void *buf, UNUSED u32 sz, UNUSED const void *ptr) { return -1; } @@ -53,23 +60,29 @@ static inline void *bpf_map_lookup_elem(bpf_map_def *map, const void *key) return __bpf_map_lookup_elem(__cgo_ctx->id, map, key); } -static inline int bpf_map_update_elem(bpf_map_def *map, const void *key, const void *val, u64 flags) +static inline int bpf_map_update_elem( + UNUSED bpf_map_def *map, UNUSED const void *key, UNUSED const void *val, UNUSED u64 flags) { return -1; } -static inline int bpf_map_delete_elem(bpf_map_def *map, const void *key) +static inline int bpf_map_delete_elem(UNUSED bpf_map_def *map, UNUSED const void *key) { return -1; } static inline int bpf_perf_event_output( - void *ctx, bpf_map_def *mapdef, unsigned long long flags, void *data, int size) + UNUSED void *ctx, + UNUSED bpf_map_def *mapdef, + UNUSED unsigned long long flags, + UNUSED void *data, + UNUSED int size) { + return 0; } -static inline int bpf_get_stackid(void *ctx, bpf_map_def *map, u64 flags) +static inline int bpf_get_stackid(UNUSED void *ctx, UNUSED bpf_map_def *map, UNUSED u64 flags) { return -1; } @@ -168,6 +181,15 @@ static long (*bpf_probe_read_kernel)(void *dst, int size, const void *unsafe_ptr __attribute__((section(name), used)) _Pragma("GCC diagnostic pop") #define EBPF_INLINE __attribute__((__always_inline__)) + #if defined(__clang__) + // Macro for loop unrolling. Expands to the appropriate pragma for clang. + // Unrolls up to 256 loop iterations. + #define UNROLL _Pragma("unroll 256") + #else + // Macro for loop unrolling. Expands to nothing for gcc. + #define UNROLL + #endif + #endif // !TESTING_COREDUMP #define MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/support/ebpf/dotnet_tracer.ebpf.c b/support/ebpf/dotnet_tracer.ebpf.c index a9b5fccd9..e41760434 100644 --- a/support/ebpf/dotnet_tracer.ebpf.c +++ b/support/ebpf/dotnet_tracer.ebpf.c @@ -44,8 +44,7 @@ bpf_map_def SEC("maps") dotnet_procs = { // currently not Garbage Collected by the runtime. Though, we have submitted also an enhancement // request to fix the nibble map format to something sane, and this might get implemented. // see: https://github.com/dotnet/runtime/issues/93550 -static EBPF_INLINE ErrorCode -dotnet_find_code_start(PerCPURecord *record, DotnetProcInfo *vi, u64 pc, u64 *code_start) +static EBPF_INLINE ErrorCode dotnet_find_code_start(PerCPURecord *record, u64 pc, u64 *code_start) { // This is an ebpf optimized implementation of EEJitManager::FindMethodCode() // https://github.com/dotnet/runtime/blob/v7.0.15/src/coreclr/vm/codeman.cpp#L4115 @@ -107,11 +106,12 @@ dotnet_find_code_start(PerCPURecord *record, DotnetProcInfo *vi, u64 pc, u64 *co // convert it from u32 to u64 offset int pos64 = (map_elements - 2) / 2; u64 val64 = scratch->map64[--pos64]; -#pragma unroll 256 + // the loop iterations is number of u64 elements minus two: // - the last element special handled earlier // - the second last element which is preloaded immediately above - for (int i = 0; i < map_elements / 2 - 2; i++) { + UNROLL for (int i = 0; i < map_elements / 2 - 2; i++) + { if (val64 != 0) { break; } @@ -146,8 +146,8 @@ dotnet_find_code_start(PerCPURecord *record, DotnetProcInfo *vi, u64 pc, u64 *co } // Decode the code start info from the entry -#pragma unroll - for (int i = 0; i < DOTNET_CODE_NIBBLES_PER_ENTRY; i++) { + UNROLL for (int i = 0; i < DOTNET_CODE_NIBBLES_PER_ENTRY; i++) + { u8 nybble = val & 0xf; if (nybble != 0) { *code_start = pc_base + pc_delta + (nybble - 1) * DOTNET_CODE_ALIGN; @@ -177,8 +177,7 @@ push_dotnet(Trace *trace, u64 code_header_ptr, u64 pc_offset, bool return_addres } // Unwind one dotnet frame -static EBPF_INLINE ErrorCode -unwind_one_dotnet_frame(PerCPURecord *record, DotnetProcInfo *vi, bool top) +static EBPF_INLINE ErrorCode unwind_one_dotnet_frame(PerCPURecord *record) { UnwindState *state = &record->state; Trace *trace = &record->trace; @@ -241,7 +240,7 @@ unwind_one_dotnet_frame(PerCPURecord *record, DotnetProcInfo *vi, bool top) } // JIT generated code, locate code start - ErrorCode error = dotnet_find_code_start(record, vi, pc, &code_start); + ErrorCode error = dotnet_find_code_start(record, pc, &code_start); if (error != ERR_OK) { DEBUG_PRINT("dotnet: --> code_start failed with %d", error); // dotnet_find_code_start incremented the metric already @@ -305,11 +304,11 @@ static EBPF_INLINE int unwind_dotnet(struct pt_regs *ctx) record->ratelimitAction = RATELIMIT_ACTION_FAST; increment_metric(metricID_UnwindDotnetAttempts); -#pragma unroll - for (int i = 0; i < DOTNET_FRAMES_PER_PROGRAM; i++) { + UNROLL for (int i = 0; i < DOTNET_FRAMES_PER_PROGRAM; i++) + { unwinder = PROG_UNWIND_STOP; - error = unwind_one_dotnet_frame(record, vi, i == 0); + error = unwind_one_dotnet_frame(record); if (error) { break; } diff --git a/support/ebpf/extmaps.h b/support/ebpf/extmaps.h index 46a236e88..3481cdc9f 100644 --- a/support/ebpf/extmaps.h +++ b/support/ebpf/extmaps.h @@ -18,7 +18,6 @@ extern bpf_map_def inhibit_events; extern bpf_map_def interpreter_offsets; extern bpf_map_def system_config; extern bpf_map_def trace_events; -extern bpf_map_def go_procs; extern bpf_map_def go_labels_procs; extern bpf_map_def cl_procs; extern bpf_map_def v8_procs; diff --git a/support/ebpf/hotspot_tracer.ebpf.c b/support/ebpf/hotspot_tracer.ebpf.c index 8121f286f..9f9b3bcd8 100644 --- a/support/ebpf/hotspot_tracer.ebpf.c +++ b/support/ebpf/hotspot_tracer.ebpf.c @@ -161,8 +161,8 @@ static EBPF_INLINE u64 hotspot_find_codeblob(const UnwindState *state, const Hot // Segment map start is put in to the PidPageMapping's file_id. segmap_start = (state->text_section_id >> HS_TSID_SEG_MAP_BIT) & HS_TSID_SEG_MAP_MASK; -#pragma unroll - for (int i = 0; i < HOTSPOT_SEGMAP_ITERATIONS; i++) { + UNROLL for (int i = 0; i < HOTSPOT_SEGMAP_ITERATIONS; i++) + { if (bpf_probe_read_user(&tag, sizeof(tag), (void *)(segmap_start + segment))) { return 0; } @@ -304,7 +304,7 @@ static EBPF_INLINE ErrorCode hotspot_handle_interpreter( } #if defined(__x86_64__) -static EBPF_INLINE void breadcrumb_fixup(HotspotUnwindInfo *ui) +static EBPF_INLINE void breadcrumb_fixup(UNUSED HotspotUnwindInfo *ui) { // Nothing to do: breadcrumbs are not a thing on X86. } @@ -411,8 +411,8 @@ hotspot_handle_prologue(const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotU #endif #if defined(__x86_64__) -static EBPF_INLINE bool -hotspot_handle_epilogue(const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotUnwindAction *action) +static EBPF_INLINE bool hotspot_handle_epilogue( + UNUSED const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotUnwindAction *action) { // On X86, use a heuristic to catch the likely spots of the epilogue. #define CODE_CUR 1 @@ -431,8 +431,8 @@ hotspot_handle_epilogue(const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotU // Is 'ret' instruction *possible* in the next 'code' bytes? // NOTE: This can find false positives because x86 is variable length // instruction set. - #pragma unroll - for (int i = CODE_CUR + 1; i < sizeof(code); i++) { + UNROLL for (int i = CODE_CUR + 1; i < sizeof(code); i++) + { if (code[i] == 0xc3) { goto found_ret; } @@ -530,8 +530,8 @@ hotspot_handle_epilogue(const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotU return false; } - #pragma unroll - for (; find_offset < EPI_LOOKBACK - 1; ++find_offset) { + UNROLL for (; find_offset < EPI_LOOKBACK - 1; ++find_offset) + { if (*(u64 *)&window[find_offset] == needle) { goto pattern_found; } @@ -574,7 +574,7 @@ pattern_found:; static EBPF_INLINE ErrorCode hotspot_handle_nmethod( const CodeBlobInfo *cbi, - Trace *trace, + UNUSED Trace *trace, HotspotUnwindInfo *ui, HotspotProcInfo *ji, HotspotUnwindAction *action, @@ -697,7 +697,7 @@ hotspot_handle_stub_fallback(const CodeBlobInfo *cbi, HotspotUnwindAction *actio } static EBPF_INLINE ErrorCode hotspot_handle_stub( - const UnwindState *state, + UNUSED const UnwindState *state, const CodeBlobInfo *cbi, HotspotUnwindInfo *ui, HotspotUnwindAction *action) @@ -940,8 +940,8 @@ static EBPF_INLINE int unwind_hotspot(struct pt_regs *ctx) int unwinder = PROG_UNWIND_STOP; ErrorCode error = ERR_OK; -#pragma unroll - for (int i = 0; i < HOTSPOT_FRAMES_PER_PROGRAM; i++) { + UNROLL for (int i = 0; i < HOTSPOT_FRAMES_PER_PROGRAM; i++) + { unwinder = PROG_UNWIND_STOP; error = hotspot_unwind_one_frame(record, ji, i == 0); if (error) { diff --git a/support/ebpf/integration_test.ebpf.c b/support/ebpf/integration_test.ebpf.c index f79db7960..407218d7b 100644 --- a/support/ebpf/integration_test.ebpf.c +++ b/support/ebpf/integration_test.ebpf.c @@ -68,8 +68,8 @@ static EBPF_INLINE void send_sample_traces(void *ctx, u64 pid, s32 kstack) trace->comm[3] = 4; trace->stack_len = MAX_FRAME_UNWINDS; trace->kernel_stack_id = kstack; -#pragma unroll - for (u64 i = 0; i < MAX_FRAME_UNWINDS; ++i) { + UNROLL for (u64 i = 0; i < MAX_FRAME_UNWINDS; ++i) + { // NOTE: this init schema eats up a lot of instructions. If we need more // space later, we can instead just init `.kind` and a few fields in the // start, middle, and end of the trace. diff --git a/support/ebpf/interpreter_dispatcher.ebpf.c b/support/ebpf/interpreter_dispatcher.ebpf.c index 4fa4d57ef..fd66e9123 100644 --- a/support/ebpf/interpreter_dispatcher.ebpf.c +++ b/support/ebpf/interpreter_dispatcher.ebpf.c @@ -126,13 +126,6 @@ bpf_map_def SEC("maps") apm_int_procs = { .max_entries = 128, }; -bpf_map_def SEC("maps") go_procs = { - .type = BPF_MAP_TYPE_HASH, - .key_size = sizeof(pid_t), - .value_size = sizeof(GoCustomLabelsOffsets), - .max_entries = 128, -}; - bpf_map_def SEC("maps") go_labels_procs = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(pid_t), @@ -147,7 +140,8 @@ bpf_map_def SEC("maps") cl_procs = { .max_entries = 128, }; -static EBPF_INLINE void *get_m_ptr_legacy(struct GoCustomLabelsOffsets *offs, UnwindState *state) +static EBPF_INLINE void * +get_m_ptr_legacy(struct GoCustomLabelsOffsets *offs, UNUSED UnwindState *state) { long res; @@ -181,7 +175,7 @@ static EBPF_INLINE void *get_m_ptr_legacy(struct GoCustomLabelsOffsets *offs, Un return m_ptr_addr; } -static EBPF_INLINE void *get_m_ptr(struct GoLabelsOffsets *offs, UnwindState *state) +static EBPF_INLINE void *get_m_ptr(struct GoLabelsOffsets *offs, UNUSED UnwindState *state) { u64 g_addr = 0; void *tls_base = NULL; @@ -226,7 +220,7 @@ static EBPF_INLINE void maybe_add_go_custom_labels_legacy(struct pt_regs *ctx, P // tail call it, in order to keep the hashing and clearing code in this program it // will tail call back to us with this bool set. if (!record->state.processed_go_labels) { - GoCustomLabelsOffsets *offsets = bpf_map_lookup_elem(&go_procs, &pid); + GoCustomLabelsOffsets *offsets = bpf_map_lookup_elem(&go_labels_procs, &pid); if (!offsets) { DEBUG_PRINT("cl: no offsets, %d not recognized as a go binary", pid); return; diff --git a/support/ebpf/luajit_tracer.ebpf.c b/support/ebpf/luajit_tracer.ebpf.c index 7a187bc31..5aa948f08 100644 --- a/support/ebpf/luajit_tracer.ebpf.c +++ b/support/ebpf/luajit_tracer.ebpf.c @@ -393,7 +393,7 @@ walk_luajit_stack(PerCPURecord *record, const LuaJITProcInfo *info, int *next_un LJState *L = &record->luajitUnwindScratch.L; TValue *prevframe = record->luajitUnwindState.prevframe; TValue *bot = L->stack + 1; -#pragma unroll + for (int i = 0; i < FRAMES_PER_WALK_LUAJIT_STACK; i++) { TValue *frame = (TValue *)(record->luajitUnwindState.frame); if (frame <= bot) { @@ -582,7 +582,7 @@ static inline __attribute__((__always_inline__)) int unwind_luajit(struct pt_reg return -1; UnwindState *state = &record->state; - int unwinder = get_next_unwinder_after_interpreter(record); + int unwinder = get_next_unwinder_after_interpreter(); ErrorCode error = ERR_OK; u32 pid = record->trace.pid; LuaJITProcInfo *info = bpf_map_lookup_elem(&luajit_procs, &pid); diff --git a/support/ebpf/native_stack_trace.ebpf.c b/support/ebpf/native_stack_trace.ebpf.c index 8e301caab..79cef79a6 100644 --- a/support/ebpf/native_stack_trace.ebpf.c +++ b/support/ebpf/native_stack_trace.ebpf.c @@ -191,8 +191,8 @@ static EBPF_INLINE ErrorCode get_stack_delta(UnwindState *state, int *addrDiff, // Do the binary search, up to 16 iterations. Deltas are paged to 64kB pages. // They can contain at most 64kB deltas even if everything is single byte opcodes. int i; -#pragma unroll - for (i = 0; i < 16; i++) { + UNROLL for (i = 0; i < 16; i++) + { if (!bsearch_step(inner_map, &lo, &hi, page_offset)) { break; } @@ -357,8 +357,7 @@ static EBPF_INLINE u64 unwind_register_address(UnwindState *state, u64 cfa, u8 o // is marked with UNWIND_COMMAND_STOP which marks entry points (main function, // thread spawn function, signal handlers, ...). #if defined(__x86_64__) -static EBPF_INLINE ErrorCode -unwind_one_frame(u64 pid, u32 frame_idx, UnwindState *state, bool *stop) +static EBPF_INLINE ErrorCode unwind_one_frame(UnwindState *state, bool *stop) { *stop = false; @@ -452,8 +451,7 @@ unwind_one_frame(u64 pid, u32 frame_idx, UnwindState *state, bool *stop) return ERR_OK; } #elif defined(__aarch64__) -static EBPF_INLINE ErrorCode -unwind_one_frame(u64 pid, u32 frame_idx, struct UnwindState *state, bool *stop) +static EBPF_INLINE ErrorCode unwind_one_frame(struct UnwindState *state, bool *stop) { *stop = false; @@ -593,8 +591,8 @@ static EBPF_INLINE int unwind_native(struct pt_regs *ctx) Trace *trace = &record->trace; int unwinder; ErrorCode error; -#pragma unroll - for (int i = 0; i < NATIVE_FRAMES_PER_PROGRAM; i++) { + UNROLL for (int i = 0; i < NATIVE_FRAMES_PER_PROGRAM; i++) + { unwinder = PROG_UNWIND_STOP; // Unwind native code @@ -620,7 +618,7 @@ static EBPF_INLINE int unwind_native(struct pt_regs *ctx) // Unwind the native frame using stack deltas. Stop if no next frame. bool stop; - error = unwind_one_frame(trace->pid, frame_idx, &record->state, &stop); + error = unwind_one_frame(&record->state, &stop); if (error || stop) { break; } diff --git a/support/ebpf/off_cpu.ebpf.c b/support/ebpf/off_cpu.ebpf.c index d260bc2fb..24fc2312c 100644 --- a/support/ebpf/off_cpu.ebpf.c +++ b/support/ebpf/off_cpu.ebpf.c @@ -20,7 +20,7 @@ bpf_map_def SEC("maps") sched_times = { // tracepoint__sched_switch serves as entry point for off cpu profiling. SEC("tracepoint/sched/sched_switch") -int tracepoint__sched_switch(void *ctx) +int tracepoint__sched_switch(UNUSED void *ctx) { u64 pid_tgid = bpf_get_current_pid_tgid(); u32 pid = pid_tgid >> 32; diff --git a/support/ebpf/perl_tracer.ebpf.c b/support/ebpf/perl_tracer.ebpf.c index 3c91f9e15..c7024962d 100644 --- a/support/ebpf/perl_tracer.ebpf.c +++ b/support/ebpf/perl_tracer.ebpf.c @@ -197,7 +197,7 @@ process_perl_frame(PerCPURecord *record, const PerlProcInfo *perlinfo, const voi return unwinder; } - if (get_next_unwinder_after_interpreter(record) != PROG_UNWIND_STOP) { + if (get_next_unwinder_after_interpreter() != PROG_UNWIND_STOP) { // If generating mixed traces, use 'sub_retop' to detect if this is the // C->Perl boundary. This is the value returned as next opcode at // https://github.com/Perl/perl5/blob/v5.32.0/pp_hot.c#L4952-L4955 @@ -209,7 +209,7 @@ process_perl_frame(PerCPURecord *record, const PerlProcInfo *perlinfo, const voi goto err; } if (retop == 0) { - unwinder = get_next_unwinder_after_interpreter(record); + unwinder = get_next_unwinder_after_interpreter(); } } @@ -286,13 +286,13 @@ static EBPF_INLINE int walk_perl_stack(PerCPURecord *record, const PerlProcInfo // If Perl stackinfo is not available, all frames have been processed, then // continue with native unwinding. if (!si) { - return get_next_unwinder_after_interpreter(record); + return get_next_unwinder_after_interpreter(); } int unwinder = PROG_UNWIND_PERL; const void *cxbase = record->perlUnwindState.cxbase; -#pragma unroll - for (u32 i = 0; i < PERL_FRAMES_PER_PROGRAM; ++i) { + UNROLL for (u32 i = 0; i < PERL_FRAMES_PER_PROGRAM; ++i) + { // Test first the stack 'cxcur' validity. Some stacks can have 'cxix=-1' // when they are being constructed or ran. if (record->perlUnwindState.cxcur < cxbase) { @@ -344,7 +344,7 @@ static EBPF_INLINE int walk_perl_stack(PerCPURecord *record, const PerlProcInfo record->perlUnwindState.stackinfo = si; prepare_perl_stack(record, perlinfo); } - unwinder = get_next_unwinder_after_interpreter(record); + unwinder = get_next_unwinder_after_interpreter(); } // Stack completed. Prepare the next one. @@ -376,7 +376,7 @@ static EBPF_INLINE int unwind_perl(struct pt_regs *ctx) return 0; } - int unwinder = get_next_unwinder_after_interpreter(record); + int unwinder = get_next_unwinder_after_interpreter(); DEBUG_PRINT("Building Perl stack for 0x%x", perlinfo->version); if (!record->perlUnwindState.stackinfo) { diff --git a/support/ebpf/php_tracer.ebpf.c b/support/ebpf/php_tracer.ebpf.c index 241c3b07f..c91617da9 100644 --- a/support/ebpf/php_tracer.ebpf.c +++ b/support/ebpf/php_tracer.ebpf.c @@ -120,18 +120,18 @@ static EBPF_INLINE int process_php_frame( static EBPF_INLINE int walk_php_stack(PerCPURecord *record, PHPProcInfo *phpinfo, bool is_jitted) { const void *execute_data = record->phpUnwindState.zend_execute_data; - bool mixed_traces = get_next_unwinder_after_interpreter(record) != PROG_UNWIND_STOP; + bool mixed_traces = get_next_unwinder_after_interpreter() != PROG_UNWIND_STOP; // If PHP data is not available, all frames have been processed, then // continue with native unwinding. if (!execute_data) { - return get_next_unwinder_after_interpreter(record); + return get_next_unwinder_after_interpreter(); } int unwinder = PROG_UNWIND_PHP; u32 type_info = 0; -#pragma unroll - for (u32 i = 0; i < FRAMES_PER_WALK_PHP_STACK; ++i) { + UNROLL for (u32 i = 0; i < FRAMES_PER_WALK_PHP_STACK; ++i) + { int metric = process_php_frame(record, phpinfo, is_jitted, execute_data, &type_info); if (metric >= 0) { increment_metric(metric); @@ -178,7 +178,7 @@ static EBPF_INLINE int walk_php_stack(PerCPURecord *record, PHPProcInfo *phpinfo unwinder = PROG_UNWIND_STOP; } } else { - unwinder = get_next_unwinder_after_interpreter(record); + unwinder = get_next_unwinder_after_interpreter(); } break; } @@ -199,7 +199,7 @@ static EBPF_INLINE int unwind_php(struct pt_regs *ctx) if (!record) return -1; - int unwinder = get_next_unwinder_after_interpreter(record); + int unwinder = get_next_unwinder_after_interpreter(); u32 pid = record->trace.pid; PHPProcInfo *phpinfo = bpf_map_lookup_elem(&php_procs, &pid); if (!phpinfo) { diff --git a/support/ebpf/python_tracer.ebpf.c b/support/ebpf/python_tracer.ebpf.c index 3ead41502..b07f2fb47 100644 --- a/support/ebpf/python_tracer.ebpf.c +++ b/support/ebpf/python_tracer.ebpf.c @@ -162,15 +162,15 @@ walk_python_stack(PerCPURecord *record, const PyProcInfo *pyinfo, int *unwinder) ErrorCode error = ERR_OK; *unwinder = PROG_UNWIND_STOP; -#pragma unroll - for (u32 i = 0; i < FRAMES_PER_WALK_PYTHON_STACK; ++i) { + UNROLL for (u32 i = 0; i < FRAMES_PER_WALK_PYTHON_STACK; ++i) + { bool continue_with_next; error = process_python_frame(record, pyinfo, &py_frame, &continue_with_next); if (error) { goto stop; } if (continue_with_next) { - *unwinder = get_next_unwinder_after_interpreter(record); + *unwinder = get_next_unwinder_after_interpreter(); goto stop; } if (!py_frame) { @@ -286,7 +286,7 @@ static EBPF_INLINE int unwind_python(struct pt_regs *ctx) return -1; ErrorCode error = ERR_OK; - int unwinder = get_next_unwinder_after_interpreter(record); + int unwinder = get_next_unwinder_after_interpreter(); Trace *trace = &record->trace; u32 pid = trace->pid; diff --git a/support/ebpf/ruby_tracer.ebpf.c b/support/ebpf/ruby_tracer.ebpf.c index c37a5ba45..171b2b313 100644 --- a/support/ebpf/ruby_tracer.ebpf.c +++ b/support/ebpf/ruby_tracer.ebpf.c @@ -56,7 +56,7 @@ static EBPF_INLINE ErrorCode walk_ruby_stack( int *next_unwinder) { if (!current_ctx_addr) { - *next_unwinder = get_next_unwinder_after_interpreter(record); + *next_unwinder = get_next_unwinder_after_interpreter(); return ERR_OK; } @@ -122,8 +122,8 @@ static EBPF_INLINE ErrorCode walk_ruby_stack( u32 iseq_size; s64 n; -#pragma unroll - for (u32 i = 0; i < FRAMES_PER_WALK_RUBY_STACK; ++i) { + UNROLL for (u32 i = 0; i < FRAMES_PER_WALK_RUBY_STACK; ++i) + { pc = 0; iseq_addr = NULL; @@ -232,7 +232,7 @@ static EBPF_INLINE int unwind_ruby(struct pt_regs *ctx) if (!record) return -1; - int unwinder = get_next_unwinder_after_interpreter(record); + int unwinder = get_next_unwinder_after_interpreter(); ErrorCode error = ERR_OK; u32 pid = record->trace.pid; RubyProcInfo *rubyinfo = bpf_map_lookup_elem(&ruby_procs, &pid); diff --git a/support/ebpf/sched_monitor.ebpf.c b/support/ebpf/sched_monitor.ebpf.c index 335daf657..63164b146 100644 --- a/support/ebpf/sched_monitor.ebpf.c +++ b/support/ebpf/sched_monitor.ebpf.c @@ -21,7 +21,7 @@ int tracepoint__sched_process_free(struct sched_process_free_ctx *ctx) { u32 pid = ctx->pid; - if (!bpf_map_lookup_elem(&reported_pids, &pid) && !pid_information_exists(ctx, pid)) { + if (!bpf_map_lookup_elem(&reported_pids, &pid) && !pid_information_exists(pid)) { // Only report PIDs that we explicitly track. This avoids sending kernel worker PIDs // to userspace. goto exit; diff --git a/support/ebpf/system_config.ebpf.c b/support/ebpf/system_config.ebpf.c index 5b705dcc2..bfd22290f 100644 --- a/support/ebpf/system_config.ebpf.c +++ b/support/ebpf/system_config.ebpf.c @@ -26,7 +26,7 @@ bpf_map_def SEC("maps") system_analysis = { // read_kernel_memory reads data from given kernel address. This is // invoked once on entry to bpf() syscall on the given pid context. SEC("tracepoint/syscalls/sys_enter_bpf") -int read_kernel_memory(void *ctx) +int read_kernel_memory(UNUSED void *ctx) { u32 key0 = 0; diff --git a/support/ebpf/tracemgmt.h b/support/ebpf/tracemgmt.h index b62dcc2c2..a88471235 100644 --- a/support/ebpf/tracemgmt.h +++ b/support/ebpf/tracemgmt.h @@ -82,7 +82,7 @@ static inline EBPF_INLINE void event_send_trigger(struct pt_regs *ctx, u32 event struct bpf_perf_event_data; // pid_information_exists checks if the given pid exists in pid_page_to_mapping_info or not. -static inline EBPF_INLINE bool pid_information_exists(void *ctx, int pid) +static inline EBPF_INLINE bool pid_information_exists(int pid) { PIDPage key = {}; key.prefixLen = BIT_WIDTH_PID + BIT_WIDTH_PAGE; @@ -261,8 +261,8 @@ static inline EBPF_INLINE PerCPURecord *get_pristine_per_cpu_record() u64 *labels_space = (u64 *)&trace->custom_labels.labels; // I'm not sure this is necessary since we only increment len after // we successfully write the label. -#pragma unroll - for (int i = 0; i < sizeof(CustomLabel) * MAX_CUSTOM_LABELS / 8; i++) { + UNROLL for (int i = 0; i < sizeof(CustomLabel) * MAX_CUSTOM_LABELS / 8; i++) + { labels_space[i] = 0; } @@ -564,7 +564,7 @@ get_next_unwinder_after_native_frame(PerCPURecord *record, int *unwinder) // get_next_unwinder_after_interpreter determines the next unwinder program to run // after an interpreter (non-native) frame sequence has been unwound. -static inline EBPF_INLINE int get_next_unwinder_after_interpreter(const PerCPURecord *record) +static inline EBPF_INLINE int get_next_unwinder_after_interpreter() { // Since interpreter-only frame decoding is no longer supported, this // currently equals to just resuming native unwinding. @@ -816,7 +816,7 @@ static inline EBPF_INLINE int collect_trace( goto exit; } - if (!pid_information_exists(ctx, pid)) { + if (!pid_information_exists(pid)) { u64 pid_tgid = (u64)pid << 32 | tid; if (report_pid(ctx, pid_tgid, RATELIMIT_ACTION_DEFAULT)) { increment_metric(metricID_NumProcNew); diff --git a/support/ebpf/tracer.ebpf.amd64 b/support/ebpf/tracer.ebpf.amd64 index cf7211df1..464b385bd 100644 Binary files a/support/ebpf/tracer.ebpf.amd64 and b/support/ebpf/tracer.ebpf.amd64 differ diff --git a/support/ebpf/tracer.ebpf.arm64 b/support/ebpf/tracer.ebpf.arm64 index 4cbf1cb4e..27dfbd115 100644 Binary files a/support/ebpf/tracer.ebpf.arm64 and b/support/ebpf/tracer.ebpf.arm64 differ diff --git a/support/ebpf/v8_tracer.ebpf.c b/support/ebpf/v8_tracer.ebpf.c index e84d79991..ca8f8eb17 100644 --- a/support/ebpf/v8_tracer.ebpf.c +++ b/support/ebpf/v8_tracer.ebpf.c @@ -245,8 +245,8 @@ static EBPF_INLINE ErrorCode unwind_one_v8_frame(PerCPURecord *record, V8ProcInf } int i; -#pragma unroll - for (i = sizeof(stk) / sizeof(stk[0]) - 1; i >= 0; i--) { + UNROLL for (i = sizeof(stk) / sizeof(stk[0]) - 1; i >= 0; i--) + { if (stk[i] >= code_start && stk[i] < code_end) { break; } @@ -335,8 +335,8 @@ static EBPF_INLINE int unwind_v8(struct pt_regs *ctx) increment_metric(metricID_UnwindV8Attempts); -#pragma unroll - for (int i = 0; i < V8_FRAMES_PER_PROGRAM; i++) { + UNROLL for (int i = 0; i < V8_FRAMES_PER_PROGRAM; i++) + { unwinder = PROG_UNWIND_STOP; error = unwind_one_v8_frame(record, vi, i == 0); diff --git a/testsupport/io.go b/testsupport/io.go index 5477b76c1..a90bc506f 100644 --- a/testsupport/io.go +++ b/testsupport/io.go @@ -18,7 +18,7 @@ func ValidateReadAtWrapperTransparency( // Samples random slices to validate within the file. r := rand.New(rand.NewPCG(0, 0)) //nolint:gosec - for i := uint(0); i < iterations; i++ { + for range iterations { // Intentionally allow slices that over-read the file to test this case. length := r.Uint64() % bufferSize start := r.Uint64() % bufferSize @@ -56,7 +56,7 @@ func ValidateReadAtWrapperTransparency( // GenerateTestInputFile generates a test input file, repeating a number sequence over and over. func GenerateTestInputFile(seqLen uint8, outputSize uint) []byte { out := make([]byte, 0, outputSize) - for i := uint(0); i < outputSize; i++ { + for i := range outputSize { out = append(out, byte(i%uint(seqLen))) } diff --git a/tools/coredump/coredump_test.go b/tools/coredump/coredump_test.go index f805ee130..3a954b477 100644 --- a/tools/coredump/coredump_test.go +++ b/tools/coredump/coredump_test.go @@ -24,7 +24,6 @@ func TestCoreDumps(t *testing.T) { require.NoError(t, err) for _, filename := range cases { - filename := filename t.Run(filename, func(t *testing.T) { testCase, err := readTestCase(filename) require.NoError(t, err) diff --git a/tools/coredump/ebpfcode.go b/tools/coredump/ebpfcode.go index 01c8464c7..c68b4ef88 100644 --- a/tools/coredump/ebpfcode.go +++ b/tools/coredump/ebpfcode.go @@ -12,124 +12,15 @@ package main // Also the tail call helper "bpf_tail_call" is overridden here, as it works in // tandem with the main entry point's setjmp. -/* -#define TESTING -#define TESTING_COREDUMP -#include -#include -#include -#include "../../support/ebpf/types.h" - -struct cgo_ctx { - jmp_buf jmpbuf; - u64 id, tp_base; - int ret; - int debug; -}; - -__thread struct cgo_ctx *__cgo_ctx; - -void bpf_log(const char *fmt, ...) -{ - void __bpf_log(const char *, int); - if (__cgo_ctx->debug) { - char msg[1024]; - size_t sz; - va_list va; - - va_start(va, fmt); - sz = vsnprintf(msg, sizeof msg, fmt, va); - __bpf_log(msg, sz); - va_end(va); - } -} - -#include "../../support/ebpf/interpreter_dispatcher.ebpf.c" -#include "../../support/ebpf/native_stack_trace.ebpf.c" -#include "../../support/ebpf/dotnet_tracer.ebpf.c" -#include "../../support/ebpf/perl_tracer.ebpf.c" -#include "../../support/ebpf/php_tracer.ebpf.c" -#include "../../support/ebpf/python_tracer.ebpf.c" -#include "../../support/ebpf/hotspot_tracer.ebpf.c" -#include "../../support/ebpf/ruby_tracer.ebpf.c" -#include "../../support/ebpf/v8_tracer.ebpf.c" -#include "../../support/ebpf/system_config.ebpf.c" -#include "../../support/ebpf/luajit_tracer.ebpf.c" -#include "../../support/ebpf/go_labels.ebpf.c" +// todo: enable -Wunused-parameter after 1.25 https://go-review.googlesource.com/c/go/+/642196 -int unwind_traces(u64 id, int debug, u64 tp_base, void *ctx) -{ - struct cgo_ctx cgoctx; - - cgoctx.id = id; - cgoctx.ret = 0; - cgoctx.debug = debug; - cgoctx.tp_base = tp_base; - __cgo_ctx = &cgoctx; - if (setjmp(cgoctx.jmpbuf) == 0) { - cgoctx.ret = native_tracer_entry(ctx); - } - __cgo_ctx = 0; - return cgoctx.ret; -} - -// We don't want to call the actual `unwind_stop` function because it'd -// require us to properly emulate all the maps required for sending frames -// to usermode. -int coredump_unwind_stop(struct bpf_perf_event_data* ctx) { - PerCPURecord *record = get_per_cpu_record(); - if (!record) - return -1; - - if (record->state.unwind_error) { - push_error(&record->trace, record->state.unwind_error); - } - - return 0; -} - -int bpf_tail_call(void *ctx, bpf_map_def *map, int index) -{ - int rc = 0; - switch (index) { - case PROG_UNWIND_STOP: - rc = coredump_unwind_stop(ctx); - break; - case PROG_UNWIND_NATIVE: - rc = unwind_native(ctx); - break; - case PROG_UNWIND_PERL: - rc = unwind_perl(ctx); - break; - case PROG_UNWIND_PHP: - rc = unwind_php(ctx); - break; - case PROG_UNWIND_PYTHON: - rc = unwind_python(ctx); - break; - case PROG_UNWIND_HOTSPOT: - rc = unwind_hotspot(ctx); - break; - case PROG_UNWIND_RUBY: - rc = unwind_ruby(ctx); - break; - case PROG_UNWIND_V8: - rc = unwind_v8(ctx); - break; - case PROG_UNWIND_DOTNET: - rc = unwind_dotnet(ctx); - break; - case PROG_UNWIND_LUAJIT: - rc = unwind_luajit(ctx); - break; - case PROG_GO_LABELS: - rc = go_labels(ctx); - break; - default: - return -1; - } - __cgo_ctx->ret = rc; - longjmp(__cgo_ctx->jmpbuf, 1); -} +/* +#cgo CFLAGS: -Wall -Wextra -Werror +#cgo CFLAGS: -Wno-address-of-packed-member +#cgo CFLAGS: -Wno-unused-label +#cgo CFLAGS: -Wno-sign-compare +#cgo CFLAGS: -Wno-unused-parameter +#cgo CFLAGS: -fno-strict-aliasing +#include "ebpfcode.h" */ import "C" diff --git a/tools/coredump/ebpfcode.h b/tools/coredump/ebpfcode.h new file mode 100644 index 000000000..c78b1926e --- /dev/null +++ b/tools/coredump/ebpfcode.h @@ -0,0 +1,99 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#define TESTING_COREDUMP +#include "../../support/ebpf/types.h" +#include +#include +#include + +struct cgo_ctx { + jmp_buf jmpbuf; + u64 id, tp_base; + int ret; + int debug; +}; + +__thread struct cgo_ctx *__cgo_ctx; + +void bpf_log(const char *fmt, ...) +{ + void __bpf_log(const char *, int); + if (__cgo_ctx->debug) { + char msg[1024]; + size_t sz; + va_list va; + + va_start(va, fmt); + sz = vsnprintf(msg, sizeof msg, fmt, va); + __bpf_log(msg, sz); + va_end(va); + } +} + +#include "../../support/ebpf/dotnet_tracer.ebpf.c" +#include "../../support/ebpf/go_labels.ebpf.c" +#include "../../support/ebpf/hotspot_tracer.ebpf.c" +#include "../../support/ebpf/interpreter_dispatcher.ebpf.c" +#include "../../support/ebpf/luajit_tracer.ebpf.c" +#include "../../support/ebpf/native_stack_trace.ebpf.c" +#include "../../support/ebpf/perl_tracer.ebpf.c" +#include "../../support/ebpf/php_tracer.ebpf.c" +#include "../../support/ebpf/python_tracer.ebpf.c" +#include "../../support/ebpf/ruby_tracer.ebpf.c" +#include "../../support/ebpf/system_config.ebpf.c" +#include "../../support/ebpf/v8_tracer.ebpf.c" + +int unwind_traces(u64 id, int debug, u64 tp_base, void *ctx) +{ + struct cgo_ctx cgoctx; + + cgoctx.id = id; + cgoctx.ret = 0; + cgoctx.debug = debug; + cgoctx.tp_base = tp_base; + __cgo_ctx = &cgoctx; + if (setjmp(cgoctx.jmpbuf) == 0) { + cgoctx.ret = native_tracer_entry(ctx); + } + __cgo_ctx = 0; + return cgoctx.ret; +} + +// We don't want to call the actual `unwind_stop` function because it'd +// require us to properly emulate all the maps required for sending frames +// to usermode. +int coredump_unwind_stop(UNUSED struct bpf_perf_event_data *ctx) +{ + (void)unwind_stop; + PerCPURecord *record = get_per_cpu_record(); + if (!record) + return -1; + + if (record->state.unwind_error) { + push_error(&record->trace, record->state.unwind_error); + } + + return 0; +} + +int bpf_tail_call(void *ctx, UNUSED bpf_map_def *map, int index) +{ + int rc = 0; + switch (index) { + case PROG_UNWIND_STOP: rc = coredump_unwind_stop(ctx); break; + case PROG_UNWIND_NATIVE: rc = unwind_native(ctx); break; + case PROG_UNWIND_PERL: rc = unwind_perl(ctx); break; + case PROG_UNWIND_PHP: rc = unwind_php(ctx); break; + case PROG_UNWIND_PYTHON: rc = unwind_python(ctx); break; + case PROG_UNWIND_HOTSPOT: rc = unwind_hotspot(ctx); break; + case PROG_UNWIND_RUBY: rc = unwind_ruby(ctx); break; + case PROG_UNWIND_V8: rc = unwind_v8(ctx); break; + case PROG_UNWIND_DOTNET: rc = unwind_dotnet(ctx); break; + case PROG_GO_LABELS: rc = go_labels(ctx); break; + case PROG_UNWIND_LUAJIT: rc = unwind_luajit(ctx); break; + default: return -1; + } + __cgo_ctx->ret = rc; + longjmp(__cgo_ctx->jmpbuf, 1); +} diff --git a/tools/coredump/json.go b/tools/coredump/json.go index 8d1c535b1..f0c5fd5cc 100644 --- a/tools/coredump/json.go +++ b/tools/coredump/json.go @@ -94,7 +94,7 @@ func readTestCase(path string) (*CoredumpTestCase, error) { } // readJSON reads a JSON file and unmarshalls it into the given object. -func readJSON(path string, to interface{}) error { +func readJSON(path string, to any) error { f, err := os.Open(path) if err != nil { return err diff --git a/tools/zstpak/lib/zstpak.go b/tools/zstpak/lib/zstpak.go index a3db4f2e7..87f14586b 100644 --- a/tools/zstpak/lib/zstpak.go +++ b/tools/zstpak/lib/zstpak.go @@ -74,7 +74,7 @@ func readFooter(input io.ReaderAt, fileSize uint64) (*footer, error) { // Convert into array of uint64. index := make([]uint64, 0, numberOfChunks) - for i := uint64(0); i < numberOfChunks; i++ { + for i := range numberOfChunks { entry := binary.LittleEndian.Uint64(rawIndex[i*8:]) if i > 0 && entry < index[i-1] { return nil, errors.New("index entries aren't monotonically increasing") diff --git a/tools/zstpak/lib/zstpak_test.go b/tools/zstpak/lib/zstpak_test.go index 50ad3cea1..0dbd23033 100644 --- a/tools/zstpak/lib/zstpak_test.go +++ b/tools/zstpak/lib/zstpak_test.go @@ -16,7 +16,7 @@ import ( func generateInputFile(seqLen uint8, outputSize uint64) []byte { out := make([]byte, 0, outputSize) - for i := uint64(0); i < outputSize; i++ { + for i := range outputSize { out = append(out, byte(i%uint64(seqLen))) } diff --git a/tpbase/assembly_decode_test.go b/tpbase/assembly_decode_test.go index 6c070b740..426bbada4 100644 --- a/tpbase/assembly_decode_test.go +++ b/tpbase/assembly_decode_test.go @@ -249,8 +249,6 @@ func TestFSBase(t *testing.T) { } for name, test := range testCases { - name := name - test := test t.Run(name, func(t *testing.T) { var analyzers []Analyzer switch test.machine { diff --git a/tpbase/libc_test.go b/tpbase/libc_test.go index 05b7f1ae9..8f5f48be7 100644 --- a/tpbase/libc_test.go +++ b/tpbase/libc_test.go @@ -248,8 +248,6 @@ func TestExtractTSDInfo(t *testing.T) { } for name, test := range testCases { - name := name - test := test t.Run(name, func(t *testing.T) { var info TSDInfo var err error diff --git a/tracehandler/tracehandler_test.go b/tracehandler/tracehandler_test.go index 1ca980e10..e40737a87 100644 --- a/tracehandler/tracehandler_test.go +++ b/tracehandler/tracehandler_test.go @@ -98,8 +98,6 @@ func TestTraceHandler(t *testing.T) { } for name, test := range tests { - name := name - test := test t.Run(name, func(t *testing.T) { r := &mockReporter{ t: t, diff --git a/tracer/helper_test.go b/tracer/helper_test.go index 10d20cd93..5d9f354dd 100644 --- a/tracer/helper_test.go +++ b/tracer/helper_test.go @@ -22,8 +22,6 @@ func TestReadCPURange(t *testing.T) { } for name, tc := range tests { - name := name - tc := tc t.Run(name, func(t *testing.T) { got, err := readCPURange(tc.input) require.NoError(t, err) diff --git a/traceutil/traceutil_test.go b/traceutil/traceutil_test.go index 6bd659161..0a59d544e 100644 --- a/traceutil/traceutil_test.go +++ b/traceutil/traceutil_test.go @@ -44,8 +44,6 @@ func TestHashTrace(t *testing.T) { } for name, testcase := range tests { - name := name - testcase := testcase t.Run(name, func(t *testing.T) { assert.Equal(t, testcase.result, HashTrace(testcase.trace)) })