diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 51c42c5ed..f21267814 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,7 +25,7 @@ jobs: uses: ./.github/workflows/env - name: Initialize CodeQL - uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: languages: go @@ -33,7 +33,7 @@ jobs: run: make - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: category: "/language:Go" timeout-minutes: 10 diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 94f611d81..0e8d41275 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@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: sarif_file: results.sarif diff --git a/Cargo.lock b/Cargo.lock index 6a4579568..0b566e729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.61" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "jobserver", @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer", "const-oid", @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -250,9 +250,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hybrid-array" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" dependencies = [ "typenum", ] @@ -270,7 +270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "serde", "serde_core", ] diff --git a/Makefile b/Makefile index 23b87d4ed..729c62299 100644 --- a/Makefile +++ b/Makefile @@ -149,7 +149,7 @@ test-deps: ($(MAKE) -C "$(testdata_dir)") || exit ; \ ) -TEST_INTEGRATION_BINARY_DIRS := tracer processmanager/ebpf support interpreter/golabels/integrationtests +TEST_INTEGRATION_BINARY_DIRS := tracer processmanager/ebpf kallsyms support interpreter/golabels/integrationtests pprof-execs: pprof_1_23 pprof_1_24 pprof_1_24_cgo pprof_1_24_cgo_pie pprof_stable pprof_stable_cgo pprof_stable_cgo_pie diff --git a/README.md b/README.md index a3bdd43a8..b7149f6b4 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,7 @@ The eBPF source code is licensed under the GPL 2.0 license. ### Emeritus - [Dmitry Filimonov](https://github.com/petethepig), Maintainer +- [Joel Höner](https://github.com/athre0z), Approver - [Tim Rühsen](https://github.com/rockdaboot), Approver For more information about the emeritus role, see the diff --git a/cmd/otelcol-ebpf-profiler/manifest.yaml b/cmd/otelcol-ebpf-profiler/manifest.yaml index e19413cd1..4613073bb 100644 --- a/cmd/otelcol-ebpf-profiler/manifest.yaml +++ b/cmd/otelcol-ebpf-profiler/manifest.yaml @@ -13,19 +13,19 @@ dist: version: dev receivers: - - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.151.0 - - gomod: go.opentelemetry.io/ebpf-profiler v0.0.202614 + - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.152.0 + - gomod: go.opentelemetry.io/ebpf-profiler v0.0.202618 import: go.opentelemetry.io/ebpf-profiler/collector exporters: - - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.151.0 - - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.151.0 - - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.151.0 + - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.152.0 + - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.152.0 + - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.152.0 providers: - - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.57.0 - - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.57.0 - - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.57.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.58.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.58.0 + - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.58.0 replaces: - go.opentelemetry.io/ebpf-profiler => ../../ diff --git a/collector/internal/metadata/generated_status.go b/collector/internal/metadata/generated_status.go index 69b9d3d7b..3b975f514 100644 --- a/collector/internal/metadata/generated_status.go +++ b/collector/internal/metadata/generated_status.go @@ -1,5 +1,7 @@ // Code generated by mdatagen. DO NOT EDIT. +// Package metadata contains the autogenerated telemetry and +// build information for the receiver/profiling component. package metadata import ( diff --git a/go.mod b/go.mod index f1399bc6a..fbbb1a382 100644 --- a/go.mod +++ b/go.mod @@ -13,41 +13,41 @@ go 1.25.0 require ( github.com/aws/aws-sdk-go-v2 v1.41.7 github.com/aws/aws-sdk-go-v2/config v1.32.17 - github.com/aws/aws-sdk-go-v2/service/s3 v1.100.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0 github.com/cilium/ebpf v0.21.0 github.com/elastic/go-freelru v0.16.0 github.com/elastic/go-perf v0.0.0-20260224073651-af0ee0c731b7 github.com/google/uuid v1.6.0 - github.com/klauspost/compress v1.18.5 + github.com/klauspost/compress v1.18.6 github.com/mdlayher/kobject v0.0.0-20200520190114-19ca17470d7d github.com/minio/sha256-simd v1.0.1 - github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260429061253-c26a8535f105 + github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260513195436-166e8d1c6b3d github.com/peterbourgon/ff/v3 v3.4.0 github.com/stretchr/testify v1.11.1 github.com/zeebo/xxh3 v1.1.0 - go.opentelemetry.io/collector/component v1.57.0 - go.opentelemetry.io/collector/component/componenttest v0.151.0 - go.opentelemetry.io/collector/confmap v1.57.0 - go.opentelemetry.io/collector/confmap/xconfmap v0.151.0 - go.opentelemetry.io/collector/consumer/consumertest v0.151.0 - go.opentelemetry.io/collector/consumer/xconsumer v0.151.0 - go.opentelemetry.io/collector/pdata v1.57.0 - go.opentelemetry.io/collector/pdata/pprofile v0.151.0 - go.opentelemetry.io/collector/receiver v1.57.0 - go.opentelemetry.io/collector/receiver/receivertest v0.151.0 - go.opentelemetry.io/collector/receiver/xreceiver v0.151.0 + go.opentelemetry.io/collector/component v1.58.0 + go.opentelemetry.io/collector/component/componenttest v0.152.0 + go.opentelemetry.io/collector/confmap v1.58.0 + go.opentelemetry.io/collector/confmap/xconfmap v0.152.0 + go.opentelemetry.io/collector/consumer/consumertest v0.152.0 + go.opentelemetry.io/collector/consumer/xconsumer v0.152.0 + go.opentelemetry.io/collector/pdata v1.58.0 + go.opentelemetry.io/collector/pdata/pprofile v0.152.0 + go.opentelemetry.io/collector/receiver v1.58.0 + go.opentelemetry.io/collector/receiver/receivertest v0.152.0 + go.opentelemetry.io/collector/receiver/xreceiver v0.152.0 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/metric v1.43.0 go.opentelemetry.io/proto/otlp v1.10.0 go.opentelemetry.io/proto/otlp/profiles/v1development v0.3.0 go.uber.org/goleak v1.3.0 go.uber.org/zap/exp v0.3.0 - golang.org/x/arch v0.26.0 - golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f - golang.org/x/mod v0.35.0 + golang.org/x/arch v0.27.0 + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a + golang.org/x/mod v0.36.0 golang.org/x/sync v0.20.0 - golang.org/x/sys v0.43.0 - google.golang.org/grpc v1.80.0 + golang.org/x/sys v0.44.0 + google.golang.org/grpc v1.81.0 google.golang.org/protobuf v1.36.11 ) @@ -90,11 +90,11 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/collector/consumer v1.57.0 // indirect - go.opentelemetry.io/collector/consumer/consumererror v0.151.0 // indirect - go.opentelemetry.io/collector/featuregate v1.57.0 // indirect - go.opentelemetry.io/collector/internal/componentalias v0.151.0 // indirect - go.opentelemetry.io/collector/pipeline v1.57.0 // indirect + go.opentelemetry.io/collector/consumer v1.58.0 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.152.0 // indirect + go.opentelemetry.io/collector/featuregate v1.58.0 // indirect + go.opentelemetry.io/collector/internal/componentalias v0.152.0 // indirect + go.opentelemetry.io/collector/pipeline v1.58.0 // indirect go.opentelemetry.io/otel/sdk v1.43.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect diff --git a/go.sum b/go.sum index de6d57eb8..6401674bb 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/ku github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23 h1:03xatSQO4+AM1lTAbnRg5OK528EUg744nW7F73U8DKw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23/go.mod h1:M8l3mwgx5ToK7wot2sBBce/ojzgnPzZXUV445gTSyE8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.100.1 h1:mxuT1xE+dI54NW3RkNjP8DUT5HXqbkiAFvfdyDFwE5c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.100.1/go.mod h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0 h1:etqBTKY581iwLL/H/S2sVgk3C9lAsTJFeXWFDsDcWOU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0/go.mod h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4= github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= @@ -78,8 +78,8 @@ github.com/jsimonetti/rtnetlink/v2 v2.0.3 h1:Jcp7GTnTPepoUAJ9+LhTa7ZiebvNS56T1Gt github.com/jsimonetti/rtnetlink/v2 v2.0.3/go.mod h1:atIkksp/9fqtf6rpAw45JnttnP2gtuH9X88WPfWfS9A= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= -github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= @@ -113,8 +113,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260429061253-c26a8535f105 h1:aH6JwjOvpluadlUOSnNtoV6ve6eWd67tBh/HO7IFu9k= -github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260429061253-c26a8535f105/go.mod h1:WPdgk1BinVdvYdkbt1KIkgDw6qUiK8CnGq+ftaJ41Ns= +github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260513195436-166e8d1c6b3d h1:qPt934sYH3CmG05SSHFXWiWTP87W60BpIvmuuiy6jTw= +github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260513195436-166e8d1c6b3d/go.mod h1:WPdgk1BinVdvYdkbt1KIkgDw6qUiK8CnGq+ftaJ41Ns= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -132,42 +132,42 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/collector/component v1.57.0 h1:WKIqx2Bs0JaAZxDEhsLradXpYxnwAxVFzWhQUmu2q3w= -go.opentelemetry.io/collector/component v1.57.0/go.mod h1:rXLy5mV78e7Gqp/dzFB+nbAFSEuJCipJfp8LbkrvOMg= -go.opentelemetry.io/collector/component/componenttest v0.151.0 h1:0rYcx913VAfD1VyVA9MKPjTrdinUaJGEaOhom8MX5zY= -go.opentelemetry.io/collector/component/componenttest v0.151.0/go.mod h1:vmhG58+J9QHOHaNu8LUD5d13LqldvkzI2jil4+lk+x0= -go.opentelemetry.io/collector/confmap v1.57.0 h1:5AuK920dJmV8zxQAiODi2JHPl2r1HmEHHMaBSC+qF5I= -go.opentelemetry.io/collector/confmap v1.57.0/go.mod h1:ifmog4kqEMM037qX04qEbom5CcxhmkadLUqhi2Vkuec= -go.opentelemetry.io/collector/confmap/xconfmap v0.151.0 h1:txpp8lH/J2sKsQXEmV0TXTIrDS7n0Bo2bPJR+mhcP3M= -go.opentelemetry.io/collector/confmap/xconfmap v0.151.0/go.mod h1:3R0Ru3Gsz6HKzjMecZPlTFDzFxaxAOl23ptm+xlsAA0= -go.opentelemetry.io/collector/consumer v1.57.0 h1:jyDh4GkYPuIXNB0UJIh33NAzZoTCVNkwS+XWdlI08P8= -go.opentelemetry.io/collector/consumer v1.57.0/go.mod h1:tJKbog9Xw/8y66aWd/C+21BMuQkOWn/lF4bzJDRC9OM= -go.opentelemetry.io/collector/consumer/consumererror v0.151.0 h1:tspiI5WE/xwYNAzR61I1XhmNYhSXdsR0Yf1Dk2MZIfQ= -go.opentelemetry.io/collector/consumer/consumererror v0.151.0/go.mod h1:dxnhPRnw3kjyweDy9pGWUNVueem15kxlvqRp0qY5k6U= -go.opentelemetry.io/collector/consumer/consumertest v0.151.0 h1:qByIVlFh9RAR/newAk/sN5i1zoIXKa2K1hRNVfye8LU= -go.opentelemetry.io/collector/consumer/consumertest v0.151.0/go.mod h1:eAGCGxkq+aABLmlr3PvMOqz3ZJbmn/lUqCbbffabSi4= -go.opentelemetry.io/collector/consumer/xconsumer v0.151.0 h1:eKIYxuPBEIrjZMAkyKBUWrlpHAE9OgxXBjq7PMSeXkE= -go.opentelemetry.io/collector/consumer/xconsumer v0.151.0/go.mod h1:9K97TkCN7XYfwKzPzktozrWc3Qw/4A1T4XgMn9TnG0c= -go.opentelemetry.io/collector/featuregate v1.57.0 h1:KPDSUKYn6MHwgyGRSGPPcW/G96HH93pxuvvPwM+R8nY= -go.opentelemetry.io/collector/featuregate v1.57.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= -go.opentelemetry.io/collector/internal/componentalias v0.151.0 h1:5IJn4XXRbjGrJCuIByHzxgHqwC0Hcl99tM+PoyYzjJY= -go.opentelemetry.io/collector/internal/componentalias v0.151.0/go.mod h1:c70sQuXHQZWSYCyc0y/VynqJdmEeBunSmEy3xfLQPWE= -go.opentelemetry.io/collector/internal/testutil v0.151.0 h1:CFjDItLuqzblItOsnK6IPSdrsOaZCaDjYpB8qWG+XHI= -go.opentelemetry.io/collector/internal/testutil v0.151.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.57.0 h1:oDWBMjEIqyJO3GJEB+iwqxj47rxDK19OKzwaFEaE4sg= -go.opentelemetry.io/collector/pdata v1.57.0/go.mod h1:wZojinP6mNhLXudH8QXx/bjWzOsKMxi/FXwnk+12G/w= -go.opentelemetry.io/collector/pdata/pprofile v0.151.0 h1:hsU0+DpkvhJh3xL1Y8CX2vAPdLMoJLiw+C+rAMsaxZc= -go.opentelemetry.io/collector/pdata/pprofile v0.151.0/go.mod h1:5zfGTQqRuaKyh2SRaZi4SV4nSD8TzY1kYoOjniOD3uk= -go.opentelemetry.io/collector/pdata/testdata v0.151.0 h1:ye09e8UMADdVrQjLgCznZxmM8ra7ciAuOCteHDzgHjc= -go.opentelemetry.io/collector/pdata/testdata v0.151.0/go.mod h1:h5+Ys9F+pf64cGt5cZCDtRsrkOnvjgpcONr8pFA3KBc= -go.opentelemetry.io/collector/pipeline v1.57.0 h1:nlevGN75Vt/Fp0HTaDjZpUHQf5QFA6o2asSmzSoBVkA= -go.opentelemetry.io/collector/pipeline v1.57.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= -go.opentelemetry.io/collector/receiver v1.57.0 h1:Aq8hcLByUOOrouekGPsxvaAHbUMxa4NM2Ok84KHjdcE= -go.opentelemetry.io/collector/receiver v1.57.0/go.mod h1:6y2UO4pmiT85z9JApUmRiP/7yX7zY5cmxbMgXvvMOA0= -go.opentelemetry.io/collector/receiver/receivertest v0.151.0 h1:U1iALsnbrAM3QdT4977y/S+Tbe68iS42qoeY5zgGXfE= -go.opentelemetry.io/collector/receiver/receivertest v0.151.0/go.mod h1:MBAEOfep8HMpdOcD5j1LOpP/GTjqz5hmZijGyYGxkGE= -go.opentelemetry.io/collector/receiver/xreceiver v0.151.0 h1:Ib86H9rBBD76wmpKQFRlwYqugvxbDtq8Lg6bVROBw4k= -go.opentelemetry.io/collector/receiver/xreceiver v0.151.0/go.mod h1:9Jqb3YKmgkZeLmHx5QBLBgdoLiu2T9q4B+o6LGTR/8U= +go.opentelemetry.io/collector/component v1.58.0 h1:GLHxFfw8jw3lRVX/h09Cc3inoR+2+XY93VxnrwHxY8Q= +go.opentelemetry.io/collector/component v1.58.0/go.mod h1:oAA7bLZUz/j1r16bQ9Cu/F+72xbQxlci8H2VmqtsAGE= +go.opentelemetry.io/collector/component/componenttest v0.152.0 h1:4o44irB1ERGRk+J5WSBvvhM9DFmIiDfC19RhPacRhOE= +go.opentelemetry.io/collector/component/componenttest v0.152.0/go.mod h1:+K7/zIUH9L6iE8mDOumJCBenPV6XxdyGIQPuvR6hIx4= +go.opentelemetry.io/collector/confmap v1.58.0 h1:lKk7XZ/BEA0eSlQWanBkhjDZewB/tu5EK2+PV/qlBws= +go.opentelemetry.io/collector/confmap v1.58.0/go.mod h1:2O/WadVBFwRzpO+3skcvjqDxD+OaS0TKKDDpPBaR4bs= +go.opentelemetry.io/collector/confmap/xconfmap v0.152.0 h1:U3h6Nf5dIaVTJTQYXGJdyIYOhaYJVEEyabXc1isU0Js= +go.opentelemetry.io/collector/confmap/xconfmap v0.152.0/go.mod h1:ff7vNJZ/kkN9pMEXRM0T9TeaKcCZE226I2NlJhKXF3I= +go.opentelemetry.io/collector/consumer v1.58.0 h1:R9qWrp4xlZTrT+Ph10vgrjnaIzkW20/RAbXs2F7PhPA= +go.opentelemetry.io/collector/consumer v1.58.0/go.mod h1:ptX5120b3Py+vqBUmjvl5VJ8yYpSQOto6Vv9b12f2d4= +go.opentelemetry.io/collector/consumer/consumererror v0.152.0 h1:ymlWj9j9KbU+x1fbnpEOd0/XRek5zsLKpNkLdmrVkYo= +go.opentelemetry.io/collector/consumer/consumererror v0.152.0/go.mod h1:snNSTrDfd8fgi1M1etHTzO3TnuqIXfuJcnRT8NUH08s= +go.opentelemetry.io/collector/consumer/consumertest v0.152.0 h1:PDYdCdbZCDWRM/XsqFTsc6BKzXwKa6+tjGe209Gv4j0= +go.opentelemetry.io/collector/consumer/consumertest v0.152.0/go.mod h1:duKfkI7aFLybPa0mFMcNtpvniZIOqIzl1CjToEJpzJU= +go.opentelemetry.io/collector/consumer/xconsumer v0.152.0 h1:+tcm9JCiQki+EpdFGxN4G8Mt0aiSLkQHYqNEXsinHd8= +go.opentelemetry.io/collector/consumer/xconsumer v0.152.0/go.mod h1:Efuqcxa8IEkXwHdwPAUYQprGWUpIO43QjoDSWKQFSiQ= +go.opentelemetry.io/collector/featuregate v1.58.0 h1:Kh6Dpgbxywv/Q3D6qPehaSxNCxvr/U/ki7CL4y3udCo= +go.opentelemetry.io/collector/featuregate v1.58.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= +go.opentelemetry.io/collector/internal/componentalias v0.152.0 h1:5uwYJ+F37s882FLzcE8ZBvCyLtcGGQsRQrNkXxYMApk= +go.opentelemetry.io/collector/internal/componentalias v0.152.0/go.mod h1:RPRS7z22S6yb+hTYzr67HoYyyB+qCKPXMaYafvdPb5s= +go.opentelemetry.io/collector/internal/testutil v0.152.0 h1:8LGwekR7mLcUDhT1ofLmdnrHRFuUa3U7PBd95ZvJEjQ= +go.opentelemetry.io/collector/internal/testutil v0.152.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.58.0 h1:5Lxut3NxKp87066Pzt+3q7+JUuFI5B3teCyLZIF8wIs= +go.opentelemetry.io/collector/pdata v1.58.0/go.mod h1:4vZtODINbC/JF3eGocnatdImzbRHseOywIcr+aULjCg= +go.opentelemetry.io/collector/pdata/pprofile v0.152.0 h1:hXpfrauR0vw2VeiYj3AGv5IySbWz56zltUtzEsLf82s= +go.opentelemetry.io/collector/pdata/pprofile v0.152.0/go.mod h1:+5gGwrj8zQuP7AGy1c8pfm8hSYTjPTdWqllZy/5rDyM= +go.opentelemetry.io/collector/pdata/testdata v0.152.0 h1:FCPsXKQJQ5ftlfJze9vtsBcFQ5sEk9tmxeBMdf6dcE0= +go.opentelemetry.io/collector/pdata/testdata v0.152.0/go.mod h1:Csws6zIBIRox4w0F4vMCPCytdN+4qg0Bdp10axC/8uw= +go.opentelemetry.io/collector/pipeline v1.58.0 h1:jgSupJSxLDdpt4RqmG9eaibOzGIu3clSVe6q4H7tRJs= +go.opentelemetry.io/collector/pipeline v1.58.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs= +go.opentelemetry.io/collector/receiver v1.58.0 h1:0GT+JVJOegia6+A14EOyCJQhXK3+/NoS8bg7gqjOadM= +go.opentelemetry.io/collector/receiver v1.58.0/go.mod h1:svgNcdk9hxFTvAPJYpydDUHx6AvCBYLjEhx0o+TabNA= +go.opentelemetry.io/collector/receiver/receivertest v0.152.0 h1:aso81TPkHZtxZffCD+kY4RWCX3uHH8knJLq+6rWSEao= +go.opentelemetry.io/collector/receiver/receivertest v0.152.0/go.mod h1:rBZkVFtjUy5pybspLnok28rPxtB5ljQS5TdcRrcd5PE= +go.opentelemetry.io/collector/receiver/xreceiver v0.152.0 h1:Brz/xsi9NV2r3etNGxfe45b2c6YrQ7JTLCHvCwaquTo= +go.opentelemetry.io/collector/receiver/xreceiver v0.152.0/go.mod h1:V6VMdl4T5QFr4hLn79iVHOC2v3dhQRJXGsVoxkB18tA= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= @@ -198,13 +198,13 @@ go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.26.0 h1:jZ6dpec5haP/fUv1kLCbuJy6dnRrfX6iVK08lZBFpk4= -golang.org/x/arch v0.26.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= +golang.org/x/arch v0.27.0 h1:0WNVcR8u9yFz8j5FvdHpgwNp3FS5U4guYdzHwEiGjoU= +golang.org/x/arch v0.27.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -219,8 +219,8 @@ golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= @@ -229,8 +229,8 @@ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 3436eed53..c4179dca7 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -14,6 +14,7 @@ tool ( require ( 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect + charm.land/lipgloss/v2 v2.0.3 // indirect codeberg.org/chavacava/garif v0.2.0 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect @@ -26,52 +27,55 @@ require ( github.com/Antonboom/nilnil v1.1.1 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect github.com/BurntSushi/toml v1.6.0 // indirect + github.com/ClickHouse/clickhouse-go-linter v1.2.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect - github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/semver/v3 v3.5.0 // indirect github.com/MirrexOne/unqueryvet v1.5.4 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect - github.com/alecthomas/chroma/v2 v2.23.1 // indirect + github.com/alecthomas/chroma/v2 v2.24.1 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect github.com/alexkohler/prealloc v1.1.0 // indirect github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/alingse/nilnesserr v0.2.0 // indirect - github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect - github.com/ashanbrown/makezero/v2 v2.1.0 // indirect - github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/ashanbrown/forbidigo/v2 v2.3.1 // indirect + github.com/ashanbrown/makezero/v2 v2.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bitfield/gotestdox v0.2.2 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.6.0 // indirect + github.com/bombsimon/wsl/v5 v5.8.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect - github.com/butuzov/ireturn v0.4.0 // indirect + github.com/butuzov/ireturn v0.4.1 // indirect github.com/butuzov/mirror v1.3.0 // indirect github.com/catenacyber/perfsprint v0.10.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.11 // indirect - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect - github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/x/ansi v0.10.1 // indirect - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect - github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/charmbracelet/colorprofile v0.4.3 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 // indirect + github.com/charmbracelet/x/ansi v0.11.7 // indirect + github.com/charmbracelet/x/term v0.2.2 // indirect + github.com/charmbracelet/x/termios v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/ckaznocha/intrange v0.3.1 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/dlclark/regexp2 v1.12.0 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.19.0 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/firefart/nonamedreturns v1.0.6 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghostiam/protogetter v0.3.20 // indirect github.com/go-critic/go-critic v0.14.3 // indirect @@ -92,14 +96,15 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golangci/asciicheck v0.5.0 // indirect - github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect + github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect - github.com/golangci/golangci-lint/v2 v2.11.4 // indirect + github.com/golangci/golangci-lint/v2 v2.12.2 // indirect github.com/golangci/golines v0.15.0 // indirect github.com/golangci/misspell v0.8.0 // indirect github.com/golangci/plugin-module-register v0.1.2 // indirect github.com/golangci/revgrep v0.8.0 // indirect + github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba // indirect github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -118,8 +123,7 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcchavezs/porto v0.7.0 // indirect - github.com/jgautheron/goconst v1.8.2 // indirect - github.com/jingyugao/rowserrcheck v1.1.1 // indirect + github.com/jgautheron/goconst v1.10.0 // indirect github.com/jjti/go-spancheck v0.6.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julz/importas v0.2.0 // indirect @@ -143,17 +147,17 @@ require ( github.com/ldez/tagliatelle v0.7.2 // indirect github.com/ldez/usetesting v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lucasb-eyer/go-colorful v1.4.0 // indirect github.com/macabu/inamedparam v0.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect - github.com/manuelarte/funcorder v0.5.0 // indirect + github.com/manuelarte/funcorder v0.6.0 // indirect github.com/maratori/testableexamples v1.0.1 // indirect github.com/maratori/testpackage v1.1.2 // indirect github.com/matoous/godox v1.1.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.23 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mgechev/revive v1.15.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -163,14 +167,14 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/moricho/tparallel v0.3.2 // indirect - github.com/muesli/termenv v0.16.0 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.23.0 // indirect github.com/otiai10/copy v1.14.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.3.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect @@ -185,17 +189,18 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/ryancurrah/gomodguard v1.4.1 // indirect + github.com/ryancurrah/gomodguard/v2 v2.1.3 // indirect github.com/ryanrolds/sqlclosecheck v0.6.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect - github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 // indirect + github.com/securego/gosec/v2 v2.26.1 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sonatard/noctx v0.5.1 // indirect - github.com/sourcegraph/go-diff v0.7.0 // indirect + github.com/sourcegraph/go-diff v0.8.0 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.10.2 // indirect @@ -207,15 +212,15 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.4.1 // indirect - github.com/tetafro/godot v1.5.4 // indirect - github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect + github.com/tetafro/godot v1.5.6 // indirect + github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect github.com/timonwong/loggercheck v0.11.0 // indirect github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/uudashr/gocognit v1.2.1 // indirect - github.com/uudashr/iface v1.4.1 // indirect + github.com/uudashr/iface v1.4.2 // indirect github.com/xen0n/gosmopolitan v1.3.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yagipy/maintidx v1.0.0 // indirect @@ -223,18 +228,19 @@ require ( github.com/ykadowak/zerologlint v0.1.5 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect go-simpler.org/musttag v0.14.0 // indirect - go-simpler.org/sloglint v0.11.1 // indirect + go-simpler.org/sloglint v0.12.0 // indirect go.augendre.info/arangolint v0.4.0 // indirect go.augendre.info/fatcontext v0.9.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/collector/cmd/builder v0.151.0 // indirect - go.opentelemetry.io/collector/cmd/mdatagen v0.151.0 // indirect - go.opentelemetry.io/collector/component v1.57.0 // indirect - go.opentelemetry.io/collector/confmap v1.57.0 // indirect - go.opentelemetry.io/collector/confmap/provider/fileprovider v1.57.0 // indirect - go.opentelemetry.io/collector/featuregate v1.57.0 // indirect - go.opentelemetry.io/collector/filter v0.151.0 // indirect - go.opentelemetry.io/collector/pdata v1.57.0 // indirect + go.opentelemetry.io/collector/cmd/builder v0.152.0 // indirect + go.opentelemetry.io/collector/cmd/mdatagen v0.152.0 // indirect + go.opentelemetry.io/collector/component v1.58.0 // indirect + go.opentelemetry.io/collector/confmap v1.58.0 // indirect + go.opentelemetry.io/collector/confmap/provider/fileprovider v1.58.0 // indirect + go.opentelemetry.io/collector/featuregate v1.58.0 // indirect + go.opentelemetry.io/collector/filter v0.152.0 // indirect + go.opentelemetry.io/collector/internal/schemagen v0.152.0 // indirect + go.opentelemetry.io/collector/pdata v1.58.0 // indirect go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 9525a0c37..2e7fd12e0 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -2,6 +2,8 @@ 4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -61,18 +63,20 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ClickHouse/clickhouse-go-linter v1.2.0 h1:zbm174up3hTKjp0wKZVnTzRiG7tSF5XZF0FJG/MuCBI= +github.com/ClickHouse/clickhouse-go-linter v1.2.0/go.mod h1:pLorS7ffPTfuUV9M0SJgfHA/h/WQPQUk2FWG9x74cQ4= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= -github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= -github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/MirrexOne/unqueryvet v1.5.4 h1:38QOxShO7JmMWT+eCdDMbcUgGCOeJphVkzzRgyLJgsQ= github.com/MirrexOne/unqueryvet v1.5.4/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= -github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/chroma/v2 v2.24.1 h1:m5ffpfZbIb++k8AqFEKy9uVgY12xIQtBsQlc6DfZJQM= +github.com/alecthomas/chroma/v2 v2.24.1/go.mod h1:l+ohZ9xRXIbGe7cIW+YZgOGbvuVLjMps/FYN/CwuabI= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= @@ -92,12 +96,10 @@ github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQ github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= -github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo= -github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c= -github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE= -github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= -github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/ashanbrown/forbidigo/v2 v2.3.1 h1:KAZijvQ7zeIBKbhikT4jCm0TLYXC4u78bTiLh/8JROI= +github.com/ashanbrown/forbidigo/v2 v2.3.1/go.mod h1:2QDkLTzU6TV937eFROamXrW92M3paehdae4HCDCOZCM= +github.com/ashanbrown/makezero/v2 v2.2.1 h1:A7uU8dgB1PA9aelTxHMfHIQ8Qev8AB3JLxJUBUsejqM= +github.com/ashanbrown/makezero/v2 v2.2.1/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -110,14 +112,14 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= -github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= +github.com/bombsimon/wsl/v5 v5.8.0 h1:JTkyfs4yl8SPejrCF2GdABXE+mO1WvM7iUYzRWlsxDs= +github.com/bombsimon/wsl/v5 v5.8.0/go.mod h1:AbOLsulgkqP4ZnitHf9gwPtCOGlrzkk0jb0uNxRSY0o= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= -github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= -github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= +github.com/butuzov/ireturn v0.4.1 h1:vWb3NO4t77iku/sjCQ/2pHTQeOmxEhjIriJqRLg1Y+I= +github.com/butuzov/ireturn v0.4.1/go.mod h1:q+DXKzTDV5guNuXLnIab9fKXizTn2miZHLhxH7V/GB4= github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ= @@ -131,22 +133,28 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk= github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= -github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= -github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= -github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= -github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= -github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= -github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= +github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= +github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318 h1:OqDqxQZliC7C8adA7KjelW3OjtAxREfeHkNcd66wpeI= +github.com/charmbracelet/ultraviolet v0.0.0-20251205161215-1948445e3318/go.mod h1:Y6kE2GzHfkyQQVCSL9r2hwokSrIlHGzZG+71+wDYSZI= +github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= +github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= +github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= +github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI= +github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= +github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= +github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2/jYn2GuM= +github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= @@ -163,8 +171,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= +github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -181,8 +189,8 @@ github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47A github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0= @@ -271,14 +279,14 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= -github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= -github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= +github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202 h1:CbTB8KpqnViI6lIXxp03Oclc4VFHi3K4BWC1TacsZ+A= +github.com/golangci/dupl v0.0.0-20260401084720-c99c5cf5c202/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.11.4 h1:GK+UlZBN5y7rh2PBnHA93XLSX6RaF7uhzJQ3JwU1wuA= -github.com/golangci/golangci-lint/v2 v2.11.4/go.mod h1:ODQDCASMA3VqfZYIbbQLpTRTzV7O/vjmIRF6u8NyFwI= +github.com/golangci/golangci-lint/v2 v2.12.2 h1:7+d1uY0bq1MU2UV3R5pW5Q7QWdcoq4naMRXM+gsJKrs= +github.com/golangci/golangci-lint/v2 v2.12.2/go.mod h1:opqHHuIcTG2R+4akzWMd4o1BnD9/1LcjICWOujr91U8= github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= @@ -287,6 +295,8 @@ github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3H github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba h1:lqtcnSMDuuJdu/LrKWi5RJzpSNLOJXYe/nzQutTI5kg= +github.com/golangci/rowserrcheck v0.0.0-20260419091836-c5f79b8a11ba/go.mod h1:sCBNcpRmhJCtbFGz49+IM3ETTFf7QdJ30AeYCd43NKk= github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= @@ -368,10 +378,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcchavezs/porto v0.7.0 h1:VncK84yxV7QZD4GdvoslzjnieSuruztGxLCmFi/Eu28= github.com/jcchavezs/porto v0.7.0/go.mod h1:tQ1cJ85cNzzZg/58VuZWOLbmrjcH1wPxkWgeBjvOq5o= -github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= -github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= -github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= -github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jgautheron/goconst v1.10.0 h1:Ptt+OoE4NaEWKhLrWrrN3IpZdGLiqaf7WLnEX/iv4Jw= +github.com/jgautheron/goconst v1.10.0/go.mod h1:0p+wv1lFOiUr0IlNNT1nrm6+8DB8u2sU6KHGzFRXHDc= github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -437,16 +445,16 @@ github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4= +github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= -github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= -github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= +github.com/manuelarte/funcorder v0.6.0 h1:0hBngc4fa1IgNiI65A7sFGkMvoMCc878RjqB5V7rWP0= +github.com/manuelarte/funcorder v0.6.0/go.mod h1:id3NDhXdQBmeqXH7eVC6Z89xS6JxvZ8kF9xUxpArU/g= github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8= github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ= github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs= @@ -459,8 +467,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= +github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgechev/revive v1.15.0 h1:vJ0HzSBzfNyPbHKolgiFjHxLek9KUijhqh42yGoqZ8Q= @@ -483,8 +491,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= -github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= @@ -495,8 +503,8 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= -github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= -github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= +github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps= +github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= @@ -510,8 +518,8 @@ github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= +github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -552,7 +560,6 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4l github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -561,6 +568,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= +github.com/ryancurrah/gomodguard/v2 v2.1.3 h1:E7sz3PJwE9Ba1reVxSpF6XLCPJZ74Kfw/LabTNM4GIA= +github.com/ryancurrah/gomodguard/v2 v2.1.3/go.mod h1:CQicdLGatWMxLX53JzoBjYlsNZhHbmLv2AVa0s2aivU= github.com/ryanrolds/sqlclosecheck v0.6.0 h1:pEyL9okISdg1F1SEpJNlrEotkTGerv5BMk7U4AG0eVg= github.com/ryanrolds/sqlclosecheck v0.6.0/go.mod h1:xyX16hsDaCMXHrMJ3JMzGf5OpDfHTOTTQrT7HOFUmeU= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= @@ -571,13 +580,11 @@ github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tM github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= -github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 h1:AoLtJX4WUtZkhhUUMFy3GgecAALp/Mb4S1iyQOA2s0U= -github.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08/go.mod h1:+XLCJiRE95ga77XInNELh2M6zQP+PdqiT9Zpm0D9Wpk= +github.com/securego/gosec/v2 v2.26.1 h1:gdkttGhQFVehqRJ8grKH4DrpqM/QlPKNHBnl8QgcEC4= +github.com/securego/gosec/v2 v2.26.1/go.mod h1:57UW4p0uoP3kxoTkhoo3axLdVAi+OWrLg/Ax/kdqtPE= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -587,8 +594,8 @@ github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+W github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/sonatard/noctx v0.5.1 h1:wklWg9c9ZYugOAk7qG4yP4PBrlQsmSLPTvW1K4PRQMs= github.com/sonatard/noctx v0.5.1/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= -github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= -github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/sourcegraph/go-diff v0.8.0 h1:ipIyu4cTsLbIrln4l0qtHA3r0a7gyK4ntKjtQytHhvY= +github.com/sourcegraph/go-diff v0.8.0/go.mod h1:hWlcO7Al+UZStZAP8rBumHpCK5ZHQ5BXsMls8p4+F5E= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -627,10 +634,10 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg= -github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= -github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= -github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/tetafro/godot v1.5.6 h1:IEkrFCwXaYHlOn4mGzGS3F3dkP6m9t0jpwqBFPIkKiA= +github.com/tetafro/godot v1.5.6/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= +github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0= +github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= github.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is= @@ -643,8 +650,8 @@ github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSW github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.1 h1:CSJynt5txTnORn/DkhiB4mZjwPuifyASC8/6Q0I/QS4= github.com/uudashr/gocognit v1.2.1/go.mod h1:acaubQc6xYlXFEMb9nWX2dYBzJ/bIjEkc1zzvyIZg5Q= -github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU= -github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= +github.com/uudashr/iface v1.4.2 h1:06Vq5RKVYThBsj0Bnw4oasMjD1r+7CE/bcKOA8dVSvg= +github.com/uudashr/iface v1.4.2/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= @@ -659,7 +666,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= @@ -668,8 +674,8 @@ go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= -go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= -go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= +go-simpler.org/sloglint v0.12.0 h1:UzWDlLWNE5FLqsvyq3tWYHuQMbqrervOhT8qPl4Mmw4= +go-simpler.org/sloglint v0.12.0/go.mod h1:jBjjC2bm8rYrs88oTRlFX497kWjJsyZWYoNaXkGRI6I= go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= @@ -683,24 +689,26 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/collector/cmd/builder v0.151.0 h1:lo4X5W6UkBJgbeXd6flut62exVlUEL9xDCxG9gIvafU= -go.opentelemetry.io/collector/cmd/builder v0.151.0/go.mod h1:5fiJ35EAPcas/kNW+YfQv5PcWzI/EDCyWgMs7FfY2f0= -go.opentelemetry.io/collector/cmd/mdatagen v0.151.0 h1:Ri31Al9yVEg1CEZJKvky7MMAugT5R/F19XI8Poa9veI= -go.opentelemetry.io/collector/cmd/mdatagen v0.151.0/go.mod h1:ZA1s+iNysgIyLGnUtkgQRAFivxr6TqK062Z0H7NnP8M= -go.opentelemetry.io/collector/component v1.57.0 h1:WKIqx2Bs0JaAZxDEhsLradXpYxnwAxVFzWhQUmu2q3w= -go.opentelemetry.io/collector/component v1.57.0/go.mod h1:rXLy5mV78e7Gqp/dzFB+nbAFSEuJCipJfp8LbkrvOMg= -go.opentelemetry.io/collector/confmap v1.57.0 h1:5AuK920dJmV8zxQAiODi2JHPl2r1HmEHHMaBSC+qF5I= -go.opentelemetry.io/collector/confmap v1.57.0/go.mod h1:ifmog4kqEMM037qX04qEbom5CcxhmkadLUqhi2Vkuec= -go.opentelemetry.io/collector/confmap/provider/fileprovider v1.57.0 h1:+y8kfU3iT21tzuhKnINDxbCzUADj7zGxZOyAa9ra0uQ= -go.opentelemetry.io/collector/confmap/provider/fileprovider v1.57.0/go.mod h1:tfjujc57jQjSQhRlPKqEPQSGC0btpIQUjyGQtDQcM7M= -go.opentelemetry.io/collector/featuregate v1.57.0 h1:KPDSUKYn6MHwgyGRSGPPcW/G96HH93pxuvvPwM+R8nY= -go.opentelemetry.io/collector/featuregate v1.57.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= -go.opentelemetry.io/collector/filter v0.151.0 h1:acMfpuJbF7tucpd1jU/4UDUSEg7HalgcudCxTow/e6E= -go.opentelemetry.io/collector/filter v0.151.0/go.mod h1:3LnA3tS8Z2EzVdkHveeP9RTu7YZybWegwij5Tr4T398= -go.opentelemetry.io/collector/internal/testutil v0.151.0 h1:CFjDItLuqzblItOsnK6IPSdrsOaZCaDjYpB8qWG+XHI= -go.opentelemetry.io/collector/internal/testutil v0.151.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.57.0 h1:oDWBMjEIqyJO3GJEB+iwqxj47rxDK19OKzwaFEaE4sg= -go.opentelemetry.io/collector/pdata v1.57.0/go.mod h1:wZojinP6mNhLXudH8QXx/bjWzOsKMxi/FXwnk+12G/w= +go.opentelemetry.io/collector/cmd/builder v0.152.0 h1:/EdXMZGUSIRhJxZzOrbCNiYes42+DR/uNHhe2xgNRP0= +go.opentelemetry.io/collector/cmd/builder v0.152.0/go.mod h1:5fiJ35EAPcas/kNW+YfQv5PcWzI/EDCyWgMs7FfY2f0= +go.opentelemetry.io/collector/cmd/mdatagen v0.152.0 h1:mDR9f7nb4YtsmgpydEJrIEL85Ftz8layoJd9k8+M4qo= +go.opentelemetry.io/collector/cmd/mdatagen v0.152.0/go.mod h1:UPaXSvvhmPGEuvdOKxOIlTTEBhrmsICwItyL6nKzyLE= +go.opentelemetry.io/collector/component v1.58.0 h1:GLHxFfw8jw3lRVX/h09Cc3inoR+2+XY93VxnrwHxY8Q= +go.opentelemetry.io/collector/component v1.58.0/go.mod h1:oAA7bLZUz/j1r16bQ9Cu/F+72xbQxlci8H2VmqtsAGE= +go.opentelemetry.io/collector/confmap v1.58.0 h1:lKk7XZ/BEA0eSlQWanBkhjDZewB/tu5EK2+PV/qlBws= +go.opentelemetry.io/collector/confmap v1.58.0/go.mod h1:2O/WadVBFwRzpO+3skcvjqDxD+OaS0TKKDDpPBaR4bs= +go.opentelemetry.io/collector/confmap/provider/fileprovider v1.58.0 h1:GTkUlglOc6e1DDXfGMZDti3s3DwpzS/EvGpXZMG0gQE= +go.opentelemetry.io/collector/confmap/provider/fileprovider v1.58.0/go.mod h1:anqn2j7ZGQZwsYA5dlc51Zu17GANAZaYRTWAwb7n7bg= +go.opentelemetry.io/collector/featuregate v1.58.0 h1:Kh6Dpgbxywv/Q3D6qPehaSxNCxvr/U/ki7CL4y3udCo= +go.opentelemetry.io/collector/featuregate v1.58.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= +go.opentelemetry.io/collector/filter v0.152.0 h1:v9TLF7p+FHrRAXcFtoVOQ9sleGoY1sdyKkUUf0c7Dmc= +go.opentelemetry.io/collector/filter v0.152.0/go.mod h1:GNDoOjdDk/HGvgzhUuGzyOtXRk8Xuv2CY+0+qay3QEA= +go.opentelemetry.io/collector/internal/schemagen v0.152.0 h1:Jv2JveUqo0EtigsFMjON69tLMp62nDg90lseRLo8rzc= +go.opentelemetry.io/collector/internal/schemagen v0.152.0/go.mod h1:EY67R+whkMGTvdbIT+YR7GrtzeKEVdMvDXhb4pLFND0= +go.opentelemetry.io/collector/internal/testutil v0.152.0 h1:8LGwekR7mLcUDhT1ofLmdnrHRFuUa3U7PBd95ZvJEjQ= +go.opentelemetry.io/collector/internal/testutil v0.152.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.58.0 h1:5Lxut3NxKp87066Pzt+3q7+JUuFI5B3teCyLZIF8wIs= +go.opentelemetry.io/collector/pdata v1.58.0/go.mod h1:4vZtODINbC/JF3eGocnatdImzbRHseOywIcr+aULjCg= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= @@ -728,8 +736,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -767,12 +773,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -806,14 +809,10 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -835,8 +834,6 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -873,9 +870,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -885,17 +880,11 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -906,8 +895,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -957,12 +944,9 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= diff --git a/interpreter/nodev8/v8.go b/interpreter/nodev8/v8.go index 62d9a8e6c..edb4a3cc7 100644 --- a/interpreter/nodev8/v8.go +++ b/interpreter/nodev8/v8.go @@ -1114,9 +1114,13 @@ func (i *v8Instance) getSFI(taggedPtr libpf.Address) (*v8SFI, error) { } else { log.Debugf("Bytecode, %d bytes, not available", length) } + typ := vms.Type.ByteArray + if vms.SourcePositionTable.TrustedByteArray { + typ = vms.Type.TrustedByteArray + } sfi.bytecodePositionTable, err = i.readFixedTablePtr( fdAddr+libpf.Address(vms.BytecodeArray.SourcePositionTable), - vms.Type.ByteArray, 1, 0) + typ, 1, 0) log.Debugf("Bytecode positions: %d bytes: %v", len(sfi.bytecodePositionTable), err) } @@ -2248,7 +2252,7 @@ func Loader(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interpr sym.Address, sym.Size, sym.Size/3) d.bytecodeSizes = make([]byte, sym.Size) d.bytecodeCount = uint8(sym.Size / 3) - if _, err = ef.ReadVirtualMemory(d.bytecodeSizes, int64(sym.Address)); err != nil { + if _, err = ef.ReadAt(d.bytecodeSizes, int64(sym.Address)); err != nil { return nil, fmt.Errorf("unable to read bytecode sizes: %v", err) } for _, opcodeLength := range d.bytecodeSizes { diff --git a/interpreter/perl/data.go b/interpreter/perl/data.go index 294342c27..3648a143e 100644 --- a/interpreter/perl/data.go +++ b/interpreter/perl/data.go @@ -162,7 +162,7 @@ func newData(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo, for i, sym := range []libpf.SymbolName{"PL_revision", "PL_version", "PL_subversion"} { addr, err := ef.LookupSymbolAddress(sym) if err == nil { - _, err = ef.ReadVirtualMemory(verBytes[i:i+1], int64(addr)) + _, err = ef.ReadAt(verBytes[i:i+1], int64(addr)) } if err != nil { return nil, fmt.Errorf("perl symbol '%s': %v", sym, err) diff --git a/kallsyms/bpf.go b/kallsyms/bpf.go new file mode 100644 index 000000000..c34c32438 --- /dev/null +++ b/kallsyms/bpf.go @@ -0,0 +1,349 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package kallsyms // import "go.opentelemetry.io/ebpf-profiler/kallsyms" + +import ( + "cmp" + "context" + "errors" + "slices" + "strings" + "sync/atomic" + "time" + + "github.com/cilium/ebpf" + "github.com/elastic/go-perf" + "go.opentelemetry.io/ebpf-profiler/internal/log" + "go.opentelemetry.io/ebpf-profiler/libpf" + "golang.org/x/sys/unix" +) + +// bpfProgPrefix is the prefix the kernel uses for all JIT'd BPF program +// symbols in /proc/kallsyms and PERF_RECORD_KSYMBOL events. +const bpfProgPrefix = "bpf_prog_" + +type bpfSymbol struct { + address libpf.Address + size uint32 + name string +} + +// bpfSymbolTable is a sorted (by address) snapshot of all known BPF program +// symbols. It is stored atomically so readers never block writers. +type bpfSymbolTable struct { + symbols []bpfSymbol +} + +// lookup returns the symbol containing addr, or ("", false) if none does. +// A symbol covers [address, address+size). +func (t *bpfSymbolTable) lookup(addr libpf.Address) (string, uint, bool) { + // Binary search for the last symbol whose address <= addr. + // BinarySearchFunc returns (index of exact match, true) or + // (insertion point, false). In both cases the candidate symbol + // is at the returned index when found, or at index-1 when not found. + idx, found := slices.BinarySearchFunc(t.symbols, addr, func(sym bpfSymbol, a libpf.Address) int { + return cmp.Compare(sym.address, a) + }) + + if !found { + // idx is the insertion point; the last symbol with address <= addr + // is one position to the left. + if idx == 0 { + return "", 0, false + } + idx-- + } + + sym := &t.symbols[idx] + if addr >= sym.address+libpf.Address(sym.size) { + return "", 0, false + } + + return sym.name, uint(addr - sym.address), true +} + +// bpfSymbolizer is responsible for getting updates from `PERF_RECORD_KSYMBOL`. +// The symbolizer is not ready to use until startMonitor is called to load the symbols. +type bpfSymbolizer struct { + records chan *perf.KSymbolRecord + events []*perf.Event + cancel context.CancelFunc + table atomic.Pointer[bpfSymbolTable] +} + +// LookupSymbol resolves addr to a BPF program symbol name and offset. +// Returns ("", 0, false) if no BPF program covers addr. +func (s *bpfSymbolizer) LookupSymbol(addr libpf.Address) (string, uint, bool) { + t := s.table.Load() + if t == nil { + return "", 0, false + } + + return t.lookup(addr) +} + +// loadBPFPrograms enumerates all loaded BPF programs via the bpf syscall and +// builds a sorted bpfSymbolTable from their JIT symbol addresses and sizes. +// Only symbols with the "bpf_prog_" prefix are included; trampolines and +// dispatchers are intentionally excluded because they are not visible at +// initial scan time and would cause misattribution. +func (s *bpfSymbolizer) loadBPFPrograms() error { + symbols := []bpfSymbol{} + + id := ebpf.ProgramID(0) + for { + var err error + id, err = ebpf.ProgramGetNextID(id) + if err != nil { + break + } + + prog, err := ebpf.NewProgramFromID(id) + if err != nil { + // Program may have been unloaded between listing and opening. + continue + } + + info, err := prog.Info() + prog.Close() + if err != nil { + continue + } + + addrs, ok := info.JitedKsymAddrs() + if !ok || len(addrs) == 0 { + continue + } + + lens, _ := info.JitedFuncLens() + + // The kernel names BPF JIT symbols as "bpf_prog__". + name := bpfProgPrefix + info.Tag + "_" + info.Name + + for i, addr := range addrs { + sym := bpfSymbol{ + address: libpf.Address(addr), + name: name, + } + + if i < len(lens) { + sym.size = lens[i] + } + + symbols = append(symbols, sym) + } + } + + slices.SortFunc(symbols, func(a, b bpfSymbol) int { + return cmp.Compare(a.address, b.address) + }) + + s.table.Store(&bpfSymbolTable{symbols: symbols}) + + return nil +} + +// startMonitor starts the update monitoring and loads bpf symbols. +func (s *bpfSymbolizer) startMonitor(ctx context.Context, onlineCPUs []int) error { + ctx, s.cancel = context.WithCancel(ctx) + + err := s.subscribe(ctx, onlineCPUs) + if err != nil { + return err + } + + err = s.loadBPFPrograms() + if err != nil { + return err + } + + go s.reloadWorker(ctx) + + return nil +} + +// subscribe subscribes to updates for bpf symbols via `PERF_RECORD_KSYMBOL`. +func (s *bpfSymbolizer) subscribe(ctx context.Context, onlineCPUs []int) error { + attr := new(perf.Attr) + perf.Dummy.Configure(attr) + attr.Options.KSymbol = true + attr.SetWakeupWatermark(1) + + s.records = make(chan *perf.KSymbolRecord) + + for _, cpu := range onlineCPUs { + event, err := perf.Open(attr, perf.AllThreads, cpu, nil) + if err != nil { + return err + } + + s.events = append(s.events, event) + + err = event.MapRing() + if err != nil { + return err + } + + err = event.Enable() + if err != nil { + return err + } + + go func(event *perf.Event) { + for { + record, err := event.ReadRecord(ctx) + if err != nil { + if ctx.Err() != nil { + return + } + + log.Errorf("Failed to read perf event: %v", err) + continue + } + + switch ksymbol := record.(type) { + case *perf.LostRecord: + // nil as a sentinel value to indicate lost events. Whenever this happens + // we trigger a full re-scan of existing bpf programs to prevent data loss. + select { + case s.records <- nil: + case <-ctx.Done(): + } + case *perf.KSymbolRecord: + if ksymbol.Type != unix.PERF_RECORD_KSYMBOL_TYPE_BPF { + continue + } + + select { + case s.records <- ksymbol: + case <-ctx.Done(): + } + default: + log.Debugf("Unexpected perf record type: %T", record) + } + + if ctx.Err() != nil { + return + } + } + }(event) + } + + return nil +} + +// reloadWorker is the goroutine handling the reloads of the bpf symbols. +func (s *bpfSymbolizer) reloadWorker(ctx context.Context) { + noTimeout := make(<-chan time.Time) + nextReload := noTimeout + for { + select { + case <-nextReload: + if err := s.loadBPFPrograms(); err == nil { + log.Debugf("Kernel symbols reloaded") + nextReload = noTimeout + } else { + log.Warnf("Failed to reload kernel symbols: %v", err) + nextReload = time.After(time.Second) + } + case record := <-s.records: + if err := s.handleBPFUpdate(record); err != nil { + log.Warnf("Error handling bpf ksymbol update: %v", err) + nextReload = time.After(time.Second) + } + case <-ctx.Done(): + return + } + } +} + +// handleBPFUpdate handles the update record from perf events. +func (s *bpfSymbolizer) handleBPFUpdate(record *perf.KSymbolRecord) error { + if record == nil { + return errors.New("lost events detected") + } + + // Only track bpf_prog_* symbols. Trampolines, dispatchers, and other + // BPF-tagged symbols are excluded because they are not present at initial + // scan time and would cause misattribution. + if !strings.HasPrefix(record.Name, bpfProgPrefix) { + return nil + } + + if record.Flags&unix.PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER != 0 { + s.removeBPFSymbol(libpf.Address(record.Addr)) + return nil + } + + s.addBPFSymbol(libpf.Address(record.Addr), record.Name, record.Len) + + return nil +} + +// addBPFSymbol inserts a new BPF program symbol into the table. +func (s *bpfSymbolizer) addBPFSymbol(addr libpf.Address, name string, size uint32) { + old := s.table.Load() + var oldSymbols []bpfSymbol + if old != nil { + oldSymbols = old.symbols + } + + // Check for a benign race: symbol already present with the same name. + idx, found := slices.BinarySearchFunc(oldSymbols, addr, func(sym bpfSymbol, a libpf.Address) int { + return cmp.Compare(sym.address, a) + }) + if found && oldSymbols[idx].name == name { + return + } + + // Insert the new symbol into the right position to maintain sorting. + newSym := bpfSymbol{address: addr, size: size, name: name} + newSymbols := make([]bpfSymbol, len(oldSymbols)+1) + copy(newSymbols, oldSymbols[:idx]) + newSymbols[idx] = newSym + copy(newSymbols[idx+1:], oldSymbols[idx:]) + + s.table.Store(&bpfSymbolTable{symbols: newSymbols}) +} + +// removeBPFSymbol removes a BPF program symbol from the table by address. +func (s *bpfSymbolizer) removeBPFSymbol(addr libpf.Address) { + old := s.table.Load() + if old == nil { + return + } + + idx, found := slices.BinarySearchFunc(old.symbols, addr, func(sym bpfSymbol, a libpf.Address) int { + return cmp.Compare(sym.address, a) + }) + if !found { + return + } + + newSymbols := make([]bpfSymbol, len(old.symbols)-1) + copy(newSymbols, old.symbols[:idx]) + copy(newSymbols[idx:], old.symbols[idx+1:]) + + s.table.Store(&bpfSymbolTable{symbols: newSymbols}) +} + +// Close frees resources associated with bpfSymbolizer. +func (s *bpfSymbolizer) Close() { + // Cancel the context first so reader goroutines and reloadWorker + // observe ctx.Done() and exit before we close the perf events. + if s.cancel != nil { + s.cancel() + } + + for _, event := range s.events { + if err := event.Disable(); err != nil { + log.Errorf("Failed to disable perf event: %v", err) + } + if err := event.Close(); err != nil { + log.Errorf("Failed to close perf event: %v", err) + } + } + + s.events = nil +} diff --git a/kallsyms/bpf_integration_test.go b/kallsyms/bpf_integration_test.go new file mode 100644 index 000000000..850678227 --- /dev/null +++ b/kallsyms/bpf_integration_test.go @@ -0,0 +1,179 @@ +//go:build integration && linux + +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package kallsyms + +import ( + "runtime" + "strings" + "testing" + "time" + + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/asm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/ebpf-profiler/libpf" + "go.opentelemetry.io/ebpf-profiler/rlimit" +) + +const ( + eventuallyWaitFor = 10 * time.Second + eventuallyTick = 100 * time.Millisecond + + dynamicProgName = "otel_dyn_test" + preexistingProgName = "otel_pre_test" +) + +// linearCPUs returns []int{0, 1, ..., n-1} for n online CPUs. +// This assumes contiguous CPU IDs, which is practical for integration tests. +// The proper parsing of /sys/devices/system/cpu/online lives in tracer/helper.go, +// but we don't want to export or duplicate it here. +func linearCPUs() []int { + cpus := make([]int, runtime.NumCPU()) + for i := range cpus { + cpus[i] = i + } + return cpus +} + +// loadSocketFilter loads a minimal BPF socket filter program with the given name. +// The program simply returns 0. The caller is responsible for closing it. +func loadSocketFilter(t *testing.T, name string) *ebpf.Program { + t.Helper() + + spec := &ebpf.ProgramSpec{ + Name: name, + Type: ebpf.SocketFilter, + License: "GPL", + Instructions: asm.Instructions{ + asm.Mov.Imm(asm.R0, 0), + asm.Return(), + }, + } + + prog, err := ebpf.NewProgram(spec) + require.NoError(t, err) + + return prog +} + +// findBPFSymbol searches the bpfSymbolTable for a symbol whose name ends with +// "_". Returns the full symbol name and its address. +func findBPFSymbol(s *bpfSymbolizer, progName string) (string, libpf.Address) { + suffix := "_" + progName + + tbl := s.table.Load() + if tbl == nil { + return "", 0 + } + + for _, sym := range tbl.symbols { + if strings.HasSuffix(sym.name, suffix) { + return sym.name, sym.address + } + } + return "", 0 +} + +// assertBPFSymbolFound polls the symbolizer until a BPF symbol matching progName +// appears, then verifies the full symbolization path (address -> symbol). +func assertBPFSymbolFound(t *testing.T, s *Symbolizer, progName string) (string, libpf.Address) { + t.Helper() + + var fullName string + var progAddr libpf.Address + require.Eventually(t, func() bool { + fullName, progAddr = findBPFSymbol(s.bpf, progName) + return fullName != "" + }, eventuallyWaitFor, eventuallyTick, + "BPF program with suffix %q not found by symbolizer", "_"+progName) + + t.Logf("Found BPF program %q at address 0x%x", fullName, progAddr) + + funcName, offset, ok := s.LookupBPFSymbol(progAddr) + require.True(t, ok, "LookupBPFSymbol failed for address 0x%x", progAddr) + assert.Equal(t, fullName, funcName) + assert.Equal(t, uint(0), offset) + + funcName, offset, ok = s.LookupBPFSymbol(progAddr + 1) + require.True(t, ok, "LookupBPFSymbol failed for address 0x%x", progAddr+1) + assert.Equal(t, fullName, funcName) + assert.Equal(t, uint(1), offset) + + return fullName, progAddr +} + +// assertBPFSymbolRemoved polls the symbolizer until the BPF symbol matching +// progName disappears. +func assertBPFSymbolRemoved(t *testing.T, s *Symbolizer, progName string) { + t.Helper() + + require.Eventually(t, func() bool { + name, _ := findBPFSymbol(s.bpf, progName) + return name == "" + }, eventuallyWaitFor, eventuallyTick, + "BPF program with suffix %q not removed from symbolizer", "_"+progName) + + t.Logf("BPF program with suffix %q successfully removed from symbolizer", "_"+progName) +} + +// TestBPFSymbolizerDynamic verifies that programs loaded after the monitor +// starts are discovered via PERF_RECORD_KSYMBOL events and that unloading +// them removes the symbols. +func TestBPFSymbolizerDynamic(t *testing.T) { + restoreRlimit, err := rlimit.MaximizeMemlock() + require.NoError(t, err) + defer restoreRlimit() + + s, err := NewSymbolizer() + require.NoError(t, err) + + err = s.bpf.startMonitor(t.Context(), linearCPUs()) + require.NoError(t, err) + defer s.bpf.Close() + + // The program hasn't been loaded yet, so the symbolizer must not know about it. + name, _ := findBPFSymbol(s.bpf, dynamicProgName) + require.Empty(t, name, "BPF program %q found before loading", dynamicProgName) + + prog := loadSocketFilter(t, dynamicProgName) + + fullName, _ := assertBPFSymbolFound(t, s, dynamicProgName) + + prog.Close() + assertBPFSymbolRemoved(t, s, dynamicProgName) + + t.Logf("Dynamic test passed: %q added and removed", fullName) +} + +// TestBPFSymbolizerPreexisting verifies that programs loaded before the +// monitor starts are discovered via the initial /proc/kallsyms parse. +func TestBPFSymbolizerPreexisting(t *testing.T) { + restoreRlimit, err := rlimit.MaximizeMemlock() + require.NoError(t, err) + defer restoreRlimit() + + // Load the program before starting the monitor. + prog := loadSocketFilter(t, preexistingProgName) + + s, err := NewSymbolizer() + require.NoError(t, err) + + err = s.bpf.startMonitor(t.Context(), linearCPUs()) + require.NoError(t, err) + defer s.bpf.Close() + + // The program was loaded before the monitor started, so it must be + // discovered from /proc/kallsyms during the initial load. + fullName, _ := assertBPFSymbolFound(t, s, preexistingProgName) + t.Logf("Preexisting program %q found from initial kallsyms load", fullName) + + // Close the program and verify the symbol is removed via perf event. + prog.Close() + assertBPFSymbolRemoved(t, s, preexistingProgName) + t.Logf("Preexisting program %q successfully removed", fullName) +} diff --git a/kallsyms/kallsyms.go b/kallsyms/kallsyms.go index efcc5e3be..c9e46cd65 100644 --- a/kallsyms/kallsyms.go +++ b/kallsyms/kallsyms.go @@ -38,6 +38,9 @@ const Kernel = "vmlinux" // from the kernel kallsyms file. const pointerBits = int(unsafe.Sizeof(libpf.Address(0)) * 8) +// maxAddr is the max address value. +const maxAddr = uint64(1< maxAddr { + return fmt.Errorf("address exceeds pointer size: %x > %x", address, maxAddr) + } if address != 0 { noSymbols = false } @@ -409,13 +417,11 @@ func (s *Symbolizer) updateSymbolsFrom(r io.Reader) error { symbols: syms[0:0], names: names[0:0], } - if moduleName != "bpf" { - oldMod, _ = getModuleByAddress(modules, libpf.Address(address)) - if oldMod != nil && !oldMod.stub && oldMod.Name() == moduleName { - oldMtime = oldMod.mtime - } else { - oldMod = nil - } + oldMod, _ = getModuleByAddress(modules, libpf.Address(address)) + if oldMod != nil && !oldMod.stub && oldMod.Name() == moduleName { + oldMtime = oldMod.mtime + } else { + oldMod = nil } if loadModuleMetadata(&newMod, moduleName, oldMtime) { // Module metadata was updated. Parse this module symbols. @@ -458,6 +464,9 @@ func (s *Symbolizer) updateSymbolsFrom(r io.Reader) error { } } } + if err := scanner.Err(); err != nil { + return fmt.Errorf("error scanning /proc/kallsyms: %w", err) + } if mod != nil { mod.finish() } @@ -486,7 +495,6 @@ func (s *Symbolizer) loadKallsyms() error { var nonsyfsModules = libpf.Set[string]{ Kernel: libpf.Void{}, - "bpf": libpf.Void{}, } // loadModules will reload module metadata. @@ -575,12 +583,6 @@ func (s *Symbolizer) reloadWorker(ctx context.Context, kobjectClient *kobject.Cl log.Warnf("Failed to reload kernel modules metadata: %v", err) nextModulesReload = time.After(10 * time.Second) } - case <-s.reloadSymbols: - // Just trigger reloading of symbols with small delay to batch - // potentially multiple module loads. - if nextKallsymsReload == noTimeout { - nextKallsymsReload = time.After(100 * time.Millisecond) - } case <-nextKallsymsReload: if err := s.loadKallsyms(); err == nil { log.Debugf("Kernel symbols reloaded") @@ -615,26 +617,28 @@ func (s *Symbolizer) pollKobjectClient(_ context.Context, kobjectClient *kobject } } -// Reload will trigger asynchronous update of modules and symbols. -func (s *Symbolizer) StartMonitor(ctx context.Context) error { +// Close frees resources associated with the Symbolizer. +func (s *Symbolizer) Close() { + s.bpf.Close() +} + +// StartMonitor starts the update monitoring for kallsyms. +func (s *Symbolizer) StartMonitor(ctx context.Context, onlineCPUs []int) error { kobjectClient, err := kobject.New() if err != nil { return fmt.Errorf("failed to create kobject netlink socket: %v", err) } + err = s.bpf.startMonitor(ctx, onlineCPUs) + if err != nil { + s.bpf.Close() + _ = kobjectClient.Close() + return err + } go s.reloadWorker(ctx, kobjectClient) go s.pollKobjectClient(ctx, kobjectClient) return nil } -// Reload triggers a non-blocking reload and update of Symbolizer -// with the recent information of /proc/kallsyms. -func (s *Symbolizer) Reload() { - select { - case s.reloadSymbols <- libpf.Void{}: - default: - } -} - // getModuleByAddress is a helper to find a Module from the sorted 'modules' // slice matching the address 'pc'. func getModuleByAddress(modules []Module, pc libpf.Address) (*Module, error) { @@ -656,7 +660,7 @@ func (s *Symbolizer) GetModuleByAddress(pc libpf.Address) (*Module, error) { return getModuleByAddress(s.modules.Load().([]Module), pc) } -// GetModuleByAddress finds the Module containing the module 'module'. +// GetModuleByName finds the Module with the given name. func (s *Symbolizer) GetModuleByName(module string) (*Module, error) { modules := s.modules.Load().([]Module) for i := range modules { @@ -667,3 +671,12 @@ func (s *Symbolizer) GetModuleByName(module string) (*Module, error) { } return nil, ErrNoModule } + +// LookupBPFSymbol resolves addr to a BPF program symbol name and offset. +// Returns ("", 0, false) if no BPF program covers addr. +func (s *Symbolizer) LookupBPFSymbol(addr libpf.Address) (string, uint, bool) { + if s.bpf == nil { + return "", 0, false + } + return s.bpf.LookupSymbol(addr) +} diff --git a/kallsyms/kallsyms_test.go b/kallsyms/kallsyms_test.go index c69471d50..dd8bed983 100644 --- a/kallsyms/kallsyms_test.go +++ b/kallsyms/kallsyms_test.go @@ -4,12 +4,16 @@ package kallsyms import ( + "cmp" "io" + "slices" "strings" "testing" "go.opentelemetry.io/ebpf-profiler/libpf" + "golang.org/x/sys/unix" + "github.com/elastic/go-perf" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -105,6 +109,156 @@ ffffffffc13fcb20 t init_xfs_fs [xfs]`)) assertSymbol(t, s, 0xffffffffc13cc610+1, "xfs", "perf_trace_xfs_attr_list_class", 1) } +// setBPFSymbols stores the given symbols in the bpfSymbolizer as a sorted +// bpfSymbolTable. This replaces the production loadBPFPrograms for tests. +func setBPFSymbols(s *bpfSymbolizer, symbols []bpfSymbol) { + sorted := make([]bpfSymbol, len(symbols)) + copy(sorted, symbols) + slices.SortFunc(sorted, func(a, b bpfSymbol) int { + return cmp.Compare(a.address, b.address) + }) + s.table.Store(&bpfSymbolTable{symbols: sorted}) +} + +// assertBPFSymbol checks that the BPF symbolizer resolves addr to the expected +// function name and offset. +func assertBPFSymbol(t *testing.T, s *Symbolizer, addr libpf.Address, eFuncName string, eOffset uint) { + t.Helper() + funcName, off, ok := s.LookupBPFSymbol(addr) + if assert.True(t, ok, "expected BPF symbol at 0x%x", addr) { + assert.Equal(t, eFuncName, funcName) + assert.Equal(t, eOffset, off) + } +} + +// assertNoBPFSymbol checks that the BPF symbolizer does not resolve addr. +func assertNoBPFSymbol(t *testing.T, s *Symbolizer, addr libpf.Address) { + t.Helper() + _, _, ok := s.LookupBPFSymbol(addr) + assert.False(t, ok, "expected no BPF symbol at 0x%x", addr) +} + +func TestBPFUpdates(t *testing.T) { + s := &Symbolizer{ + bpf: &bpfSymbolizer{}, + } + + bpfSymbols := []bpfSymbol{ + {address: 0xffffffc080f26228, size: 512, name: "bpf_prog_00354c172d366337_sd_devices"}, + {address: 0xffffffc080f26430, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_egress"}, + {address: 0xffffffc080f264d8, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_ingress"}, + {address: 0xffffffc080f28490, size: 512, name: "bpf_prog_56551fa66be1356a_sd_devices"}, + {address: 0xffffffc080f2867c, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_egress"}, + {address: 0xffffffc080f2871c, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_ingress"}, + {address: 0xffffffc080f2da64, size: 512, name: "bpf_prog_00354c172d366337_sd_devices"}, + {address: 0xffffffc080f304a0, size: 512, name: "bpf_prog_5be112cdf63b0d8c_sysctl_monitor"}, + {address: 0xffffffc080f3089c, size: 512, name: "bpf_prog_292e0637857c1257_cut_last"}, + {address: 0xffffffc080f3096c, size: 512, name: "bpf_prog_a97c143260cd9940_sd_devices"}, + {address: 0xffffffc080f32f4c, size: 512, name: "bpf_prog_79c5319176ee7ce5_sd_devices"}, + {address: 0xffffffc080f331e4, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_egress"}, + {address: 0xffffffc080f33288, size: 512, name: "bpf_prog_772db7720b2728e9_sd_fw_ingress"}, + {address: 0xffffffc080f35f1c, size: 512, name: "bpf_prog_461f9f5162fd8042_sd_devices"}, + {address: 0xffffffc080f3629c, size: 512, name: "bpf_prog_b8f4fb5f08605bc5"}, + } + + setBPFSymbols(s.bpf, bpfSymbols) + + // Adding a symbol at the end with a known size of 12288 bytes. This ensures + // that an address 10240 bytes into the symbol is covered even though that + // far exceeds a single page past the symbol start. + const lastSymAddr = libpf.Address(0xffffffc080f38288) + const lastSymSize = uint32(12288) + err := s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: uint64(lastSymAddr), + Len: lastSymSize, + Name: "bpf_prog_05cbe5ca7b74dd09_sys_enter", + }) + require.NoError(t, err) + + // exact symbol match + assertBPFSymbol(t, s, lastSymAddr, "bpf_prog_05cbe5ca7b74dd09_sys_enter", 0) + + // 10240 bytes into the last symbol must resolve correctly + assertBPFSymbol(t, s, lastSymAddr+10240, "bpf_prog_05cbe5ca7b74dd09_sys_enter", 10240) + + // address beyond the symbol's end must not resolve + assertNoBPFSymbol(t, s, lastSymAddr+libpf.Address(lastSymSize)) + + // remove the added symbol + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: uint64(lastSymAddr), + Name: "bpf_prog_05cbe5ca7b74dd09_sys_enter", + Flags: unix.PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER, + }) + require.NoError(t, err) + + // the address goes poof + assertNoBPFSymbol(t, s, lastSymAddr) + + // add it back + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: uint64(lastSymAddr), + Len: lastSymSize, + Name: "bpf_prog_05cbe5ca7b74dd09_sys_enter", + }) + require.NoError(t, err) + + // find a pre-existing symbol by aiming slightly above its start + assertBPFSymbol(t, s, 0xffffffc080f3089e, "bpf_prog_292e0637857c1257_cut_last", 0x2) + + // remove the pre-existing symbol + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: 0xffffffc080f3089c, + Name: "bpf_prog_292e0637857c1257_cut_last", + Flags: unix.PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER, + }) + require.NoError(t, err) + + // the address no longer resolves (previous symbol ends before 0x3089e) + assertNoBPFSymbol(t, s, 0xffffffc080f3089e) + + // put the removed symbol back + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: 0xffffffc080f3089c, + Len: 512, + Name: "bpf_prog_292e0637857c1257_cut_last", + }) + require.NoError(t, err) + + // and it's right there where we put it + assertBPFSymbol(t, s, 0xffffffc080f3089e, "bpf_prog_292e0637857c1257_cut_last", 0x2) + + // checking for lost symbols triggering full reload + err = s.bpf.handleBPFUpdate(nil) + assert.NotNil(t, err) + + // trampolines and non-bpf_prog_ symbols are silently ignored + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: 0xffffffc080f26226, + Name: "bpf_trampoline_6442536467", + }) + require.NoError(t, err) + assertNoBPFSymbol(t, s, 0xffffffc080f26226) + + // a bpf_prog_ symbol added before existing ones is found correctly + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: 0xffffffc080f26000, + Len: 512, + Name: "bpf_prog_earliest", + }) + require.NoError(t, err) + assertBPFSymbol(t, s, 0xffffffc080f26000, "bpf_prog_earliest", 0) + + // removing it works + err = s.bpf.handleBPFUpdate(&perf.KSymbolRecord{ + Addr: 0xffffffc080f26000, + Name: "bpf_prog_earliest", + Flags: unix.PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER, + }) + require.NoError(t, err) + assertNoBPFSymbol(t, s, 0xffffffc080f26000) +} + func BenchmarkSort(b *testing.B) { r := strings.NewReader(`0000000000000000 A __per_cpu_start 0000000000001000 A cpu_debug_store diff --git a/libpf/frametype.go b/libpf/frametype.go index 53337a22f..af47bf6cc 100644 --- a/libpf/frametype.go +++ b/libpf/frametype.go @@ -53,6 +53,8 @@ const ( GoFrame FrameType = support.FrameMarkerGo // BEAMFrame identifies the BEAM interpreter frames. BEAMFrame FrameType = support.FrameMarkerBEAM + // LuaJITFrame identifies the LuaJIT interpreter frames. + LuaJITFrame FrameType = support.FrameMarkerLuaJIT ) const ( diff --git a/libpf/frametype_test.go b/libpf/frametype_test.go index 730e56aa6..ef27447b1 100644 --- a/libpf/frametype_test.go +++ b/libpf/frametype_test.go @@ -13,7 +13,7 @@ func TestFrameTypeFromString(t *testing.T) { // Simple check whether all FrameType values can be converted to string and back. for _, ft := range []FrameType{ UnknownFrame, PHPFrame, PythonFrame, NativeFrame, KernelFrame, HotSpotFrame, RubyFrame, - PerlFrame, V8Frame, DotnetFrame} { + PerlFrame, V8Frame, DotnetFrame, LuaJITFrame} { t.Run(ft.String(), func(t *testing.T) { name := ft.String() result := FrameTypeFromString(name) diff --git a/libpf/interpretertype.go b/libpf/interpretertype.go index ff581e117..7ee09a75f 100644 --- a/libpf/interpretertype.go +++ b/libpf/interpretertype.go @@ -31,6 +31,8 @@ const ( V8 InterpreterType = support.FrameMarkerV8 // Dotnet identifies the Dotnet interpreter. Dotnet InterpreterType = support.FrameMarkerDotnet + // LuaJIT identifies the LuaJIT interpreter. + LuaJIT InterpreterType = support.FrameMarkerLuaJIT // Go identifies Go code. Go InterpreterType = support.FrameMarkerGo // BEAM identifies the BEAM interpreter. @@ -73,6 +75,7 @@ var interpreterTypeToString = map[InterpreterType]string{ Dotnet: "dotnet", BEAM: "beam", APMInt: "apm-integration", + LuaJIT: "luajit", Go: "go", GoLabels: "go-labels", } diff --git a/libpf/pfelf/file.go b/libpf/pfelf/file.go index 16ba04235..cc82c2a34 100644 --- a/libpf/pfelf/file.go +++ b/libpf/pfelf/file.go @@ -27,6 +27,7 @@ import ( "fmt" "hash/crc32" "io" + "os" "path/filepath" "runtime" "runtime/debug" @@ -67,6 +68,9 @@ type File struct { // elfReader is the ReadAt implementation used for this File elfReader io.ReaderAt + // mmapReader is the mmap reader for this File if available + mmapReader *mmap.ReaderAt + // ehFrame is a pointer to the PT_GNU_EH_FRAME segment of the ELF ehFrame *Prog @@ -170,7 +174,7 @@ type Section struct { // Open opens the named file using os.Open and prepares it for use as an ELF binary. func Open(name string) (*File, error) { - f, err := mmap.Open(name) + f, err := os.Open(name) if err != nil { return nil, err } @@ -185,6 +189,9 @@ func Open(name string) (*File, error) { // Close closes the File. func (f *File) Close() (err error) { + if f.mmapReader != nil { + f.mmapReader.Close() + } if f.closer != nil { err = f.closer.Close() f.closer = nil @@ -235,6 +242,11 @@ func newFile(r io.ReaderAt, closer io.Closer, return nil, err } + if osFile, ok := r.(*os.File); ok { + // Attempt to mmap the file if possible + f.mmapReader, _ = mmap.OpenFile(osFile) + } + f.Progs = make([]Prog, hdr.Phnum) virtualBase := ^uint64(0) numROData := 0 @@ -251,7 +263,7 @@ func newFile(r io.ReaderAt, closer io.Closer, Memsz: ph.Memsz, Align: ph.Align, } - p.elfReader = r + p.elfReader = f.getReader() if p.Type == elf.PT_LOAD { if p.Vaddr < virtualBase { @@ -362,12 +374,21 @@ func (_ NoMmapCloser) Close() error { // keep slices returned by Section.Data() and Prog.Data() after File has been // GCd. The returned Close() will release the reference on data. func (f *File) Take() io.Closer { - if mapping, ok := f.elfReader.(*mmap.ReaderAt); ok { - return mapping.Take() + if f.mmapReader != nil { + return f.mmapReader.Take() } return NoMmapCloser{} } +// getReader returns the mmap reader if available, or otherwise the underlying +// reader (typically os.File). +func (f *File) getReader() io.ReaderAt { + if f.mmapReader != nil { + return f.mmapReader + } + return f.elfReader +} + // LoadSections loads the ELF file sections func (f *File) LoadSections() error { if f.InsideCore { @@ -412,7 +433,7 @@ func (f *File) LoadSections() error { Entsize: sh.Entsize, FileSize: sh.Size, } - s.elfReader = f.elfReader + s.elfReader = f.getReader() } // Load the section name string table @@ -487,34 +508,19 @@ func (f *File) VirtualMemory(addr int64, sz, maxSize int) ([]byte, error) { return nil, fmt.Errorf("no matching segment for 0x%x", uint64(addr)) } -// SymbolData returns the data associated with given dynamic symbol. -// The backing mmapped data is returned if possible, otherwise a maximum of -// maxCopy bytes of the symbol data will read to newly allocated buffer. -func (f *File) SymbolData(name libpf.SymbolName, maxCopy int) (*libpf.Symbol, []byte, error) { +// SymbolData reads and returns the data associated with given dynamic symbol. +// The maximum data read is capped to maxSize. +func (f *File) SymbolData(name libpf.SymbolName, maxSize int) (*libpf.Symbol, []byte, error) { sym, err := f.LookupSymbol(name) if err != nil { return nil, nil, err } - symSize := int(sym.Size) - if symSize > maxCopy { - // Truncate read size if not memory mapped data. - if _, ok := f.elfReader.(*mmap.ReaderAt); !ok { - symSize = maxCopy - } - } - data, err := f.VirtualMemory(int64(sym.Address), symSize, maxCopy) - return sym, data, err -} - -// ReadVirtualMemory reads bytes from given virtual address -func (f *File) ReadVirtualMemory(p []byte, addr int64) (int, error) { - if len(p) == 0 { - return 0, nil - } - if ph := f.findVirtualAddressProg(uint64(addr)); ph != nil { - return ph.ReadAt(p, addr-int64(ph.Vaddr)) + data := make([]byte, min(int(sym.Size), maxSize)) + _, err = f.ReadAt(data, int64(sym.Address)) + if err != nil { + return nil, nil, err } - return 0, fmt.Errorf("no matching segment for 0x%x", uint64(addr)) + return sym, data, nil } // EHFrame constructs a Program header with the EH Frame sections @@ -546,7 +552,7 @@ func (f *File) EHFrame() (*Prog, error) { Memsz: ph.Memsz - offs, Align: ph.Align, }, - elfReader: f.elfReader, + elfReader: f.getReader(), }, nil } return nil, errors.New("no PT_LOAD segment for PT_GNU_EH_FRAME found") @@ -597,7 +603,7 @@ func (f *File) GoVersion() (string, error) { if !f.IsGolang() { return "", nil } - bi, err := buildinfo.Read(f.elfReader) + bi, err := buildinfo.Read(f.getReader()) if err != nil { return "", err } @@ -887,11 +893,6 @@ func (ph *Prog) ReadAt(p []byte, off int64) (n int, err error) { return n, nil } -// Open returns a new ReadSeeker reading the ELF program body. -func (ph *Prog) Open() io.ReadSeeker { - return io.NewSectionReader(ph, 0, 1<<63-1) -} - // Data loads the whole program header referenced data, and returns it as slice. func (ph *Prog) Data(maxSize uint) ([]byte, error) { if mapping, ok := ph.elfReader.(*mmap.ReaderAt); ok { @@ -954,8 +955,8 @@ func (sh *Section) Data(maxSize uint) ([]byte, error) { // SetDontNeed sets the flag MADV_DONTNEED on the mmapped data. func (f *File) SetDontNeed() { - if mapping, ok := f.elfReader.(*mmap.ReaderAt); ok { - if err := mapping.SetMadvDontNeed(); err != nil { + if f.mmapReader != nil { + if err := f.mmapReader.SetMadvDontNeed(); err != nil { log.Errorf("Failed to set MADV_DONTNEED: %v", err) } } @@ -963,7 +964,13 @@ func (f *File) SetDontNeed() { // ReadAt reads bytes from given virtual address func (f *File) ReadAt(p []byte, addr int64) (int, error) { - return f.ReadVirtualMemory(p, addr) + if len(p) == 0 { + return 0, nil + } + if ph := f.findVirtualAddressProg(uint64(addr)); ph != nil { + return ph.ReadAt(p, addr-int64(ph.Vaddr)) + } + return 0, fmt.Errorf("no matching segment for 0x%x", uint64(addr)) } // GetRemoteMemory returns RemoteMemory interface for the core dump @@ -980,7 +987,7 @@ func (f *File) readAndMatchSymbol(n uint32, name libpf.SymbolName) (libpf.Symbol // Read symbol descriptor and expected name symSz := int64(unsafe.Sizeof(sym)) - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&sym), + if _, err := f.ReadAt(pfunsafe.FromPointer(&sym), f.symbolsAddr+int64(n)*symSz); err != nil { return libpf.Symbol{}, false } @@ -1028,7 +1035,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { // blog link (on top of this file) for details how this works. hdr := &f.gnuHash.header if hdr.numBuckets == 0 { - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(hdr), f.gnuHash.addr); err != nil { + if _, err := f.ReadAt(pfunsafe.FromPointer(hdr), f.gnuHash.addr); err != nil { return nil, err } if hdr.numBuckets == 0 || hdr.bloomSize == 0 { @@ -1042,7 +1049,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { var bloom uint h := calcGNUHash(symbol) offs := f.gnuHash.addr + int64(unsafe.Sizeof(gnuHashHeader{})) - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&bloom), offs+ + if _, err := f.ReadAt(pfunsafe.FromPointer(&bloom), offs+ ptrSize*int64((h/ptrSizeBits)%hdr.bloomSize)); err != nil { return nil, err } @@ -1055,7 +1062,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { // Read the initial symbol index to start looking from offs += int64(hdr.bloomSize) * int64(unsafe.Sizeof(bloom)) var i uint32 - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&i), + if _, err := f.ReadAt(pfunsafe.FromPointer(&i), offs+4*int64(h%hdr.numBuckets)); err != nil { return nil, err } @@ -1068,7 +1075,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { h |= 1 for { var h2 uint32 - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&h2), offs); err != nil { + if _, err := f.ReadAt(pfunsafe.FromPointer(&h2), offs); err != nil { return nil, err } // Do a full match of the symbol if the symbol hash matches @@ -1088,7 +1095,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { // Normal ELF symbol lookup. Refer to ELF spec, part 2 "Hash Table" (2-19) hdr := &f.sysvHash.header if hdr.numBuckets == 0 { - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(hdr), f.sysvHash.addr); err != nil { + if _, err := f.ReadAt(pfunsafe.FromPointer(hdr), f.sysvHash.addr); err != nil { return nil, err } if hdr.numBuckets == 0 { @@ -1099,7 +1106,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { offs := f.sysvHash.addr + int64(unsafe.Sizeof(*hdr)) h := calcSysvHash(symbol) bucket := int64(h % hdr.numBuckets) - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&i), offs+4*bucket); err != nil { + if _, err := f.ReadAt(pfunsafe.FromPointer(&i), offs+4*bucket); err != nil { return nil, err } offs += 4 * int64(hdr.numBuckets) @@ -1107,7 +1114,7 @@ func (f *File) LookupSymbol(symbol libpf.SymbolName) (*libpf.Symbol, error) { if s, ok := f.readAndMatchSymbol(i, symbol); ok { return &s, nil } - if _, err := f.ReadVirtualMemory(pfunsafe.FromPointer(&i), offs+4*int64(i)); err != nil { + if _, err := f.ReadAt(pfunsafe.FromPointer(&i), offs+4*int64(i)); err != nil { return nil, err } } diff --git a/libpf/pfelf/internal/mmap/mmap.go b/libpf/pfelf/internal/mmap/mmap.go index fb648078b..984fc8e4d 100644 --- a/libpf/pfelf/internal/mmap/mmap.go +++ b/libpf/pfelf/internal/mmap/mmap.go @@ -90,6 +90,12 @@ func Open(filename string) (*ReaderAt, error) { return nil, err } defer f.Close() + + return OpenFile(f) +} + +// OpenFile memory-maps the OS file for reading. +func OpenFile(f *os.File) (*ReaderAt, error) { fi, err := f.Stat() if err != nil { return nil, err @@ -107,10 +113,10 @@ func Open(filename string) (*ReaderAt, error) { }, nil } if size < 0 { - return nil, fmt.Errorf("mmap: file %q has negative size", filename) + return nil, fmt.Errorf("mmap: negative file size") } if size != int64(int(size)) { - return nil, fmt.Errorf("mmap: file %q is too large", filename) + return nil, fmt.Errorf("mmap: too large file size") } data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED) diff --git a/nativeunwind/elfunwindinfo/elfehframe_test.go b/nativeunwind/elfunwindinfo/elfehframe_test.go index e0d0cc557..427d31cdd 100644 --- a/nativeunwind/elfunwindinfo/elfehframe_test.go +++ b/nativeunwind/elfunwindinfo/elfehframe_test.go @@ -178,3 +178,71 @@ func TestParseCIE(t *testing.T) { }) } } + +func TestGetUnwindInfoX86_RegisterRA(t *testing.T) { + tests := []struct { + name string + regs vmRegs + expected sdtypes.UnwindInfo + }{ + { + name: "Standard RA=CFA-8", + regs: vmRegs{ + cfa: vmReg{reg: x86RegRSP, off: 16}, // rsp+16 + ra: vmReg{reg: regCFA, off: -8}, + fp: vmReg{reg: regCFA, off: -16}, + }, + expected: sdtypes.UnwindInfo{ + Flags: 0, + BaseReg: support.UnwindRegSp, + Param: 16, + AuxBaseReg: support.UnwindRegCfa, + AuxParam: -16, + }, + }, + { + name: "Register-based RA (RDI)", + regs: vmRegs{ + cfa: vmReg{reg: x86RegRSP, off: 8}, // rsp+8 + ra: vmReg{reg: x86RegRDI, off: 0}, + fp: vmReg{reg: regCFA, off: 0}, + }, + expected: sdtypes.UnwindInfo{ + Flags: support.UnwindFlagRegisterRA | support.UnwindFlagLeafOnly, + BaseReg: support.UnwindRegSp, + Param: 8, + AuxBaseReg: support.UnwindRegX86RDI, + }, + }, + { + name: "Invalid RA", + regs: vmRegs{ + cfa: vmReg{reg: x86RegRSP, off: 20}, + ra: vmReg{reg: regCFA, off: -16}, // Not -8 + fp: vmReg{reg: regCFA, off: 0}, + }, + expected: sdtypes.UnwindInfoInvalid, + }, + { + name: "Exact __vfork FDE: CFA=RSP+0 with RA=RDI", + regs: vmRegs{ + cfa: vmReg{reg: x86RegRSP, off: 0}, // DW_CFA_def_cfa_offset: 0 + ra: vmReg{reg: x86RegRDI, off: 0}, // DW_CFA_register: r16 in r5 + fp: vmReg{reg: regUndefined}, // FP not specified + }, + expected: sdtypes.UnwindInfo{ + Flags: support.UnwindFlagRegisterRA | support.UnwindFlagLeafOnly, + BaseReg: support.UnwindRegSp, + Param: 0, + AuxBaseReg: support.UnwindRegX86RDI, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := tt.regs.getUnwindInfoX86() + assert.Equal(t, tt.expected, actual) + }) + } +} diff --git a/nativeunwind/elfunwindinfo/elfehframe_x86.go b/nativeunwind/elfunwindinfo/elfehframe_x86.go index fb060b66e..73074a571 100644 --- a/nativeunwind/elfunwindinfo/elfehframe_x86.go +++ b/nativeunwind/elfunwindinfo/elfehframe_x86.go @@ -93,16 +93,22 @@ func getUnwinderRegX86(reg uleb128) uint8 { switch reg { case x86RegRAX: return support.UnwindRegX86RAX + case x86RegRDI: + return support.UnwindRegX86RDI + case x86RegRBP: + return support.UnwindRegFp + case x86RegRSP: + return support.UnwindRegSp + case x86RegR8: + return support.UnwindRegX86R8 case x86RegR9: return support.UnwindRegX86R9 case x86RegR11: return support.UnwindRegX86R11 + case x86RegR13: + return support.UnwindRegX86R13 case x86RegR15: return support.UnwindRegX86R15 - case x86RegRBP: - return support.UnwindRegFp - case x86RegRSP: - return support.UnwindRegSp case x86RegRIP: return support.UnwindRegPc case regCFA: @@ -126,33 +132,39 @@ func (regs *vmRegs) getUnwindInfoX86() sdtypes.UnwindInfo { // condition in samples is statistically unlikely. return sdtypes.UnwindInfoStop } - // Filter invalid RSP based CFAs - if regs.cfa.reg == x86RegRSP && regs.cfa.off == 0 { - return sdtypes.UnwindInfoInvalid - } + info := sdtypes.UnwindInfo{} - // The CFI allows having Return Address (RA) be recoverable via an expression, - // but the eBPF currently supports the ABI standard RA=CFA-8 only. Verify that - // we are not in any weird hand woven assembly which is not supported. - if regs.ra.reg != regCFA || regs.ra.off != -8 { + // The Return Address (RA) is usually recoverable via an ABI standard RA=CFA-8. + // But some functions (like __vfork) use a register to store the RA. + raReg := getUnwinderRegX86(regs.ra.reg) + if raReg != support.UnwindRegInvalid && raReg != support.UnwindRegCfa { + info.Flags |= support.UnwindFlagRegisterRA + info.AuxBaseReg = raReg + if raReg != support.UnwindRegFp && raReg != support.UnwindRegSp { + info.Flags |= support.UnwindFlagLeafOnly + } + } else if regs.ra.reg == regCFA && regs.ra.off == -8 { + // Standard CFA-8 + } else { + // Not the standard CFA-8 and not a supported register return sdtypes.UnwindInfoInvalid } - info := sdtypes.UnwindInfo{} - // Determine unwind info for frame pointer - switch regs.fp.reg { - case regCFA: - // Check that RBP is between CFA and stack top - if regs.cfa.reg != x86RegRSP || (regs.fp.off < 0 && regs.fp.off >= -regs.cfa.off) { - info.AuxBaseReg = support.UnwindRegCfa - info.AuxParam = int32(regs.fp.off) - } - case regExprReg: - // expression: RBP+offrbp - if r, _, offrbp, _ := splitOff(regs.fp.off); uleb128(r) == x86RegRBP { - info.AuxBaseReg = support.UnwindRegFp - info.AuxParam = int32(offrbp) + if info.Flags&support.UnwindFlagRegisterRA == 0 { + switch regs.fp.reg { + case regCFA: + // Check that RBP is between CFA and stack top + if regs.cfa.reg != x86RegRSP || (regs.fp.off < 0 && regs.fp.off >= -regs.cfa.off) { + info.AuxBaseReg = support.UnwindRegCfa + info.AuxParam = int32(regs.fp.off) + } + case regExprReg: + // expression: RBP+offrbp + if r, _, offrbp, _ := splitOff(regs.fp.off); uleb128(r) == x86RegRBP { + info.AuxBaseReg = support.UnwindRegFp + info.AuxParam = int32(offrbp) + } } } diff --git a/nativeunwind/elfunwindinfo/stackdeltaextraction.go b/nativeunwind/elfunwindinfo/stackdeltaextraction.go index 0bc4b63c2..6108d00d7 100644 --- a/nativeunwind/elfunwindinfo/stackdeltaextraction.go +++ b/nativeunwind/elfunwindinfo/stackdeltaextraction.go @@ -127,10 +127,13 @@ func (ee *elfExtractor) extractDebugDeltas() (err error) { return err } -func isLibCrypto(elfFile *pfelf.File) bool { +func isLibGenericRegsAllowed(elfFile *pfelf.File) bool { if name, err := elfFile.DynString(elf.DT_SONAME); err == nil && len(name) == 1 { - // Allow generic register CFA for openssl libcrypto - return strings.HasPrefix(name[0], "libcrypto.so.") + // Allow generic register CFA for openssl libcrypto, glibc and musl + n := name[0] + return strings.HasPrefix(n, "libcrypto.so.") || + strings.HasPrefix(n, "libc.so.") || + strings.HasPrefix(n, "ld-linux-") } return false } @@ -191,7 +194,7 @@ func extractFile(elfFile *pfelf.File, elfRef *pfelf.Reference, file: elfFile, deltas: &deltas, hooks: &filter, - allowGenericRegs: isLibCrypto(elfFile), + allowGenericRegs: isLibGenericRegsAllowed(elfFile), } if entryLength := detectEntry(elfFile); entryLength != 0 { diff --git a/nativeunwind/stackdeltatypes/stackdeltatypes.go b/nativeunwind/stackdeltatypes/stackdeltatypes.go index fd4f0ed11..334e9fa75 100644 --- a/nativeunwind/stackdeltatypes/stackdeltatypes.go +++ b/nativeunwind/stackdeltatypes/stackdeltatypes.go @@ -76,6 +76,15 @@ type IntervalData struct { func (deltas *StackDeltaArray) AddEx(delta StackDelta, sorted bool) { num := len(*deltas) if delta.Info.Flags&support.UnwindFlagCommand != 0 { + if delta.Info.Param == support.UnwindCommandSignal { + // EBPF code does a -1 fixup for return addresses. + // To match the signal handler function injected into + // stack, the signal handler stack delta must start one + // byte earlier to accommodate for the ebpf fixup. + // C-libraries will have a 'nop' inserted to make sure + // nothing conflicts. + delta.Address-- + } // FP information is invalid/unused for command opcodes. // But DWARF info often leaves bogus data there, so resetting it // reduces the number of unique Info contents generated. diff --git a/processmanager/ebpf/ebpf.go b/processmanager/ebpf/ebpf.go index 5bbfbfaab..6b8459b7e 100644 --- a/processmanager/ebpf/ebpf.go +++ b/processmanager/ebpf/ebpf.go @@ -640,7 +640,7 @@ func (impl *ebpfMapsImpl) UpdatePidPageMappingInfo(pid libpf.PID, prefix lpm.Pre // DeletePidPageMappingInfo removes the elements specified by prefixes from eBPF map // pid_page_to_mapping_info and returns the number of elements removed. -func (impl *ebpfMapsImpl) DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (int, +func (impl *ebpfMapsImpl) DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (uint64, error, ) { if impl.hasLPMTrieBatchOperations { @@ -656,11 +656,11 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm return impl.DeletePidPageMappingInfoSingle(pid, prefixes) } -func (impl *ebpfMapsImpl) DeletePidPageMappingInfoSingle(pid libpf.PID, prefixes []lpm.Prefix) (int, +func (impl *ebpfMapsImpl) DeletePidPageMappingInfoSingle(pid libpf.PID, prefixes []lpm.Prefix) (uint64, error, ) { cKey := &support.PIDPage{} - var deleted int + var deleted uint64 var combinedErrors error for _, prefix := range prefixes { *cKey = getPIDPageFromPrefix(pid, prefix) @@ -674,7 +674,7 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfoSingle(pid libpf.PID, prefixes return deleted, combinedErrors } -func (impl *ebpfMapsImpl) DeletePidPageMappingInfoBatch(pid libpf.PID, prefixes []lpm.Prefix) (int, +func (impl *ebpfMapsImpl) DeletePidPageMappingInfoBatch(pid libpf.PID, prefixes []lpm.Prefix) (uint64, error, ) { // Prepare all keys based on the given prefixes. @@ -685,7 +685,13 @@ func (impl *ebpfMapsImpl) DeletePidPageMappingInfoBatch(pid libpf.PID, prefixes deleted, err := impl.PidPageToMappingInfo.BatchDelete( ptrCastMarshaler[support.PIDPage](cKeys), nil) - return deleted, impl.trackMapError(metrics.IDPidPageToMappingInfoBatchDelete, err) + + // BatchDelete returns a count of deleted entries, so this should never happen. + if deleted < 0 { + err = errors.Join(err, fmt.Errorf("negative batch delete count: %d", deleted)) + deleted = 0 + } + return uint64(deleted), impl.trackMapError(metrics.IDPidPageToMappingInfoBatchDelete, err) } // LookupPidPageInformation returns the fileID and bias for a given pid and page combination from diff --git a/processmanager/ebpfapi/ebpf.go b/processmanager/ebpfapi/ebpf.go index 0f8398138..aa244f728 100644 --- a/processmanager/ebpfapi/ebpf.go +++ b/processmanager/ebpfapi/ebpf.go @@ -51,7 +51,7 @@ type EbpfHandler interface { // DeletePidPageMappingInfo removes the elements specified by prefixes from eBPF map // pid_page_to_mapping_info and returns the number of elements removed. - DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (int, error) + DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (uint64, error) // CollectMetrics returns gathered errors for changes to eBPF maps. CollectMetrics() []metrics.Metric diff --git a/processmanager/execinfomanager/synthdeltas.go b/processmanager/execinfomanager/synthdeltas.go index 29b384bbb..bf42045a8 100644 --- a/processmanager/execinfomanager/synthdeltas.go +++ b/processmanager/execinfomanager/synthdeltas.go @@ -48,14 +48,14 @@ func createVDSOSyntheticRecordArm64(ef *pfelf.File) sdtypes.IntervalData { if sym.Name == "__kernel_rt_sigreturn" { deltas = append( deltas, - sdtypes.StackDelta{Address: addr, Info: sdtypes.UnwindInfoSignal}, + sdtypes.StackDelta{Address: addr - 1, Info: sdtypes.UnwindInfoSignal}, sdtypes.StackDelta{Address: addr + sym.Size, Info: sdtypes.UnwindInfoLR}, ) return true } // Determine if LR is on stack code := make([]byte, sym.Size) - if _, err := ef.ReadVirtualMemory(code, int64(sym.Address)); err != nil { + if _, err := ef.ReadAt(code, int64(sym.Address)); err != nil { return true } diff --git a/processmanager/execinfomanager/synthdeltas_test.go b/processmanager/execinfomanager/synthdeltas_test.go index d16c65c1d..272498986 100644 --- a/processmanager/execinfomanager/synthdeltas_test.go +++ b/processmanager/execinfomanager/synthdeltas_test.go @@ -28,7 +28,7 @@ func TestVDSOArm64(t *testing.T) { {Address: 0x7e4, Info: sdtypes.UnwindInfoLR}, {Address: 0x800, Info: frameSize16}, {Address: 0x80c, Info: sdtypes.UnwindInfoLR}, - {Address: 0x8f8, Info: sdtypes.UnwindInfoSignal}, + {Address: 0x8f7, Info: sdtypes.UnwindInfoSignal}, {Address: 0x900, Info: sdtypes.UnwindInfoLR}, }, } diff --git a/processmanager/processinfo.go b/processmanager/processinfo.go index f0d5966c9..855717e86 100644 --- a/processmanager/processinfo.go +++ b/processmanager/processinfo.go @@ -318,7 +318,7 @@ func (pm *ProcessManager) processRemovedMapping(pid libpf.PID, m *Mapping) uint6 fileID := host.FileIDFromLibpf(mf.File.Value().FileID) pm.eim.DecRef(fileID) - return uint64(deleted) + return deleted } // Caller is responsible to hold pm.mu write lock to avoid race conditions. @@ -456,11 +456,11 @@ func (pm *ProcessManager) processPIDExit(pid libpf.PID) { err = errors.Join(err, fmt.Errorf("failed to delete dummy prefix for PID %d: %v", pid, err2)) } - pm.pidPageToMappingInfoSize -= uint64(deleted) for idx := range info.mappings { - pm.processRemovedMapping(pid, &info.mappings[idx]) + deleted += pm.processRemovedMapping(pid, &info.mappings[idx]) } + pm.pidPageToMappingInfoSize -= min(pm.pidPageToMappingInfoSize, deleted) pm.processRemovedInterpreters(pid, libpf.Set[util.OnDiskFileIdentifier]{}) } @@ -651,7 +651,7 @@ func (pm *ProcessManager) SynchronizeProcess(pr process.Process) { for _, m := range mpRemove { numChanges += pm.processRemovedMapping(pid, m) } - pm.pidPageToMappingInfoSize -= numChanges + pm.pidPageToMappingInfoSize -= min(pm.pidPageToMappingInfoSize, numChanges) pm.mu.Lock() pm.processRemovedInterpreters(pid, interpretersValid) pm.mu.Unlock() diff --git a/reporter/internal/pdata/generate_test.go b/reporter/internal/pdata/generate_test.go index 15a495693..802fdf9dd 100644 --- a/reporter/internal/pdata/generate_test.go +++ b/reporter/internal/pdata/generate_test.go @@ -847,16 +847,6 @@ func TestGenerate_Validate(t *testing.T) { err = proto.Unmarshal(contents, &data) require.NoError(t, err) - // Fix for protobuf unmarshaling for ConformanceChecker: The first attribute - // table entry must have a nil Value,but protobuf unmarshaling creates a - // non-nil but empty AnyValue. Explicitly set it to nil. - if data.Dictionary != nil && len(data.Dictionary.AttributeTable) > 0 { - firstAttr := data.Dictionary.AttributeTable[0] - if firstAttr.KeyStrindex == 0 && firstAttr.UnitStrindex == 0 { - firstAttr.Value = nil - } - } - err = (profcheck.ConformanceChecker{ CheckDictionaryDuplicates: true, CheckSampleTimestampShape: true}).Check(&data) diff --git a/support/ebpf/beam_tracer.ebpf.c b/support/ebpf/beam_tracer.ebpf.c index 7ca6088b0..9cac2cae6 100644 --- a/support/ebpf/beam_tracer.ebpf.c +++ b/support/ebpf/beam_tracer.ebpf.c @@ -3,7 +3,7 @@ #include "types.h" // The number of frames to unwind per frame-unwinding eBPF program. -#define BEAM_FRAMES_PER_PROGRAM 8 +#define BEAM_FRAMES_PER_PROGRAM 60 // The max number of loops to unroll when searching for the correct CodeHeader. // Should be log base 2 of a reasonable number of modules to binary-search through. diff --git a/support/ebpf/bpfdefs.h b/support/ebpf/bpfdefs.h index 91a261c6d..96d560082 100644 --- a/support/ebpf/bpfdefs.h +++ b/support/ebpf/bpfdefs.h @@ -132,7 +132,7 @@ static long (*bpf_probe_read_kernel)(void *dst, int size, const void *unsafe_ptr #define printt(fmt, ...) \ ({ \ - const char ____fmt[] = fmt; \ + static const char ____fmt[] = fmt; \ bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ }) diff --git a/support/ebpf/dotnet_tracer.ebpf.c b/support/ebpf/dotnet_tracer.ebpf.c index d88f06e66..ed3fc3a6f 100644 --- a/support/ebpf/dotnet_tracer.ebpf.c +++ b/support/ebpf/dotnet_tracer.ebpf.c @@ -10,10 +10,10 @@ #include "types.h" // The number of dotnet frames to unwind per frame-unwinding eBPF program. -#define DOTNET_FRAMES_PER_PROGRAM 6 +#define DOTNET_FRAMES_PER_PROGRAM 45 // The number of dotnet10+ frames to unwind per frame-unwinding eBPF program. -#define DOTNET10_FRAMES_PER_PROGRAM 9 +#define DOTNET10_FRAMES_PER_PROGRAM 68 // The maximum dotnet frame length used in heuristic to validate FP #define DOTNET_MAX_FRAME_LENGTH 8192 diff --git a/support/ebpf/frametypes.h b/support/ebpf/frametypes.h index aae841d98..3d7f90cfc 100644 --- a/support/ebpf/frametypes.h +++ b/support/ebpf/frametypes.h @@ -33,6 +33,8 @@ #define FRAME_MARKER_GO 0xB // Indicates a BEAM frame #define FRAME_MARKER_BEAM 0xC +// Indicates a LuaJIT frame +#define FRAME_MARKER_LUAJIT 0xD // Frame flags // Indicates that this frame is an error frame. diff --git a/support/ebpf/hotspot_tracer.ebpf.c b/support/ebpf/hotspot_tracer.ebpf.c index 6bdc2d2f7..afbb3f1cc 100644 --- a/support/ebpf/hotspot_tracer.ebpf.c +++ b/support/ebpf/hotspot_tracer.ebpf.c @@ -69,7 +69,7 @@ typedef enum HotspotUnwindAction { } HotspotUnwindAction; // The number of hotspot frames to unwind per frame-unwinding eBPF program. -#define HOTSPOT_FRAMES_PER_PROGRAM 4 +#define HOTSPOT_FRAMES_PER_PROGRAM 30 // The maximum number of HotSpot segmap lookup iterations. This is directly proportional // to the size of JIT method code size. The longest sequence seen so far is from JDK8, diff --git a/support/ebpf/interpreter_dispatcher.ebpf.c b/support/ebpf/interpreter_dispatcher.ebpf.c index ae9a1c9a7..8bcfb7b25 100644 --- a/support/ebpf/interpreter_dispatcher.ebpf.c +++ b/support/ebpf/interpreter_dispatcher.ebpf.c @@ -34,7 +34,7 @@ struct perf_progs_t { __uint(max_entries, NUM_TRACER_PROGS); } perf_progs SEC(".maps"); -// report_events notifies user space about events (GENERIC_PID and RELOAD_KALLSYMS). +// report_events notifies user space about events (GENERIC_PID). // // As a key the CPU number is used and the value represents a perf event file descriptor. // Information transmitted is the event type only. We use 0 as the number of max entries diff --git a/support/ebpf/kallsyms.ebpf.c b/support/ebpf/kallsyms.ebpf.c deleted file mode 100644 index 8e2eee667..000000000 --- a/support/ebpf/kallsyms.ebpf.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "bpfdefs.h" -#include "tracemgmt.h" -#include "types.h" - -// kprobe__kallsyms notifies user space about changes to kallsyms. -SEC("kprobe/kallsysms") -int kprobe__kallsyms(void *ctx) -{ - event_send_trigger(ctx, EVENT_TYPE_RELOAD_KALLSYMS); - return 0; -} diff --git a/support/ebpf/native_stack_trace.ebpf.c b/support/ebpf/native_stack_trace.ebpf.c index dde9ec8af..1c015b77e 100644 --- a/support/ebpf/native_stack_trace.ebpf.c +++ b/support/ebpf/native_stack_trace.ebpf.c @@ -75,7 +75,7 @@ struct unwind_info_array_t { } unwind_info_array SEC(".maps"); // The number of native frames to unwind per frame-unwinding eBPF program. -#define NATIVE_FRAMES_PER_PROGRAM 5 +#define NATIVE_FRAMES_PER_PROGRAM 10 // The decision whether to unwind native stacks or interpreter stacks is made by checking if a given // PC address falls into the "interpreter loop" of an interpreter. This map helps identify such @@ -157,22 +157,17 @@ static EBPF_INLINE void *get_stack_delta_map(int mapID) // Get the stack offset of the given instruction. static EBPF_INLINE ErrorCode get_stack_delta(UnwindState *state, int *addrDiff, u32 *unwindInfo) { - u64 exe_id = state->text_section_id; + unsigned long exe_id = state->text_section_id; + unsigned long offset = state->text_section_offset - (int)state->return_address; // Look up the stack delta page information for this address. StackDeltaPageKey key = {}; - key.fileID = state->text_section_id; - key.page = state->text_section_offset & ~STACK_DELTA_PAGE_MASK; - DEBUG_PRINT( - "Look up stack delta for %lx:%lx", - (unsigned long)state->text_section_id, - (unsigned long)state->text_section_offset); + key.fileID = exe_id; + key.page = offset & ~STACK_DELTA_PAGE_MASK; + DEBUG_PRINT("Look up stack delta for %lx:%lx", exe_id, offset); StackDeltaPageInfo *info = bpf_map_lookup_elem(&stack_delta_page_to_info, &key); if (!info) { - DEBUG_PRINT( - "Failure to look up stack delta page fileID %lx, page %lx", - (unsigned long)key.fileID, - (unsigned long)key.page); + DEBUG_PRINT("Failure to look up stack delta page fileID %lx, page %lx", exe_id, offset); state->error_metric = metricID_UnwindNativeErrLookupTextSection; return ERR_NATIVE_LOOKUP_TEXT_SECTION; } @@ -180,23 +175,21 @@ static EBPF_INLINE ErrorCode get_stack_delta(UnwindState *state, int *addrDiff, void *outer_map = get_stack_delta_map(info->mapID); if (!outer_map) { DEBUG_PRINT( - "Failure to look up outer map for text section %lx in mapID %d", - (unsigned long)exe_id, - (int)info->mapID); + "Failure to look up outer map for text section %lx in mapID %d", exe_id, (int)info->mapID); state->error_metric = metricID_UnwindNativeErrLookupStackDeltaOuterMap; return ERR_NATIVE_LOOKUP_STACK_DELTA_OUTER_MAP; } void *inner_map = bpf_map_lookup_elem(outer_map, &exe_id); if (!inner_map) { - DEBUG_PRINT("Failure to look up inner map for text section %lx", (unsigned long)exe_id); + DEBUG_PRINT("Failure to look up inner map for text section %lx", exe_id); state->error_metric = metricID_UnwindNativeErrLookupStackDeltaInnerMap; return ERR_NATIVE_LOOKUP_STACK_DELTA_INNER_MAP; } // Preinitialize the idx for the index to use for page without any deltas. u32 idx = info->firstDelta; - u16 page_offset = state->text_section_offset & STACK_DELTA_PAGE_MASK; + u16 page_offset = offset & STACK_DELTA_PAGE_MASK; if (info->numDeltas) { // Page has deltas, so find the correct one to use using binary search. u32 lo = info->firstDelta; @@ -358,6 +351,8 @@ static EBPF_INLINE ErrorCode unwind_one_frame(PerCPURecord *record, bool *stop) if (bpf_probe_read_user(rt_regs, sizeof(record->rt_regs), (void *)(state->sp + 40))) { goto err_native_pc_read; } + state->rdi = rt_regs[8]; + state->r8 = rt_regs[0]; state->rax = rt_regs[13]; state->r9 = rt_regs[1]; state->r11 = rt_regs[3]; @@ -399,10 +394,18 @@ static EBPF_INLINE ErrorCode unwind_one_frame(PerCPURecord *record, bool *stop) // the previous FP address if any. state->cfa = cfa = unwind_calc_register_with_deref( state, info->baseReg, param, (info->flags & UNWIND_FLAG_DEREF_CFA) != 0); - u64 fpa = unwind_calc_register(state, info->auxBaseReg, info->auxParam); + u64 aux = unwind_calc_register(state, info->auxBaseReg, info->auxParam); + + if (info->flags & UNWIND_FLAG_REGISTER_RA) { + // RA was recovered from a register (e.g. __vfork stores RA in %rdi). + // FP is not preserved across such calls, clear it for the next frame. + state->pc = aux; + state->fp = 0; + goto nonleaf_frame_ok; + } - if (fpa) { - bpf_probe_read_user(&state->fp, sizeof(state->fp), (void *)fpa); + if (aux) { + bpf_probe_read_user(&state->fp, sizeof(state->fp), (void *)aux); } else if (info->baseReg == UNWIND_REG_FP) { // FP used for recovery, but no new FP value received, clear FP state->fp = 0; @@ -414,6 +417,7 @@ static EBPF_INLINE ErrorCode unwind_one_frame(PerCPURecord *record, bool *stop) increment_metric(metricID_UnwindNativeErrPCRead); return ERR_NATIVE_PC_READ; } +nonleaf_frame_ok: state->sp = cfa; unwinder_mark_nonleaf_frame(state); frame_ok: diff --git a/support/ebpf/perl_tracer.ebpf.c b/support/ebpf/perl_tracer.ebpf.c index 9c22f5f38..164cca4f5 100644 --- a/support/ebpf/perl_tracer.ebpf.c +++ b/support/ebpf/perl_tracer.ebpf.c @@ -34,7 +34,7 @@ #include "types.h" // The number of Perl frames to unwind per frame-unwinding eBPF program. -#define PERL_FRAMES_PER_PROGRAM 12 +#define PERL_FRAMES_PER_PROGRAM 90 // PERL SI types definitions // https://github.com/Perl/perl5/blob/v5.32.0/cop.h#L1017-L1035 diff --git a/support/ebpf/php_tracer.ebpf.c b/support/ebpf/php_tracer.ebpf.c index ce9687f7c..8c3a898b6 100644 --- a/support/ebpf/php_tracer.ebpf.c +++ b/support/ebpf/php_tracer.ebpf.c @@ -7,7 +7,7 @@ // The number of PHP frames to unwind per frame-unwinding eBPF program. If // we start running out of instructions in the walk_php_stack program, one // option is to adjust this number downwards. -#define FRAMES_PER_WALK_PHP_STACK 19 +#define FRAMES_PER_WALK_PHP_STACK 143 // The type_info flag for executor data to indicate top-of-stack frames // as defined in php/Zend/zend_compile.h. diff --git a/support/ebpf/python_tracer.ebpf.c b/support/ebpf/python_tracer.ebpf.c index 9eb455728..2f261a450 100644 --- a/support/ebpf/python_tracer.ebpf.c +++ b/support/ebpf/python_tracer.ebpf.c @@ -9,7 +9,7 @@ // The number of Python frames to unwind per frame-unwinding eBPF program. If // we start running out of instructions in the walk_python_stack program, one // option is to adjust this number downwards. -#define FRAMES_PER_WALK_PYTHON_STACK 12 +#define FRAMES_PER_WALK_PYTHON_STACK 90 // Forward declaration to avoid warnings like // "declaration of 'struct pt_regs' will not be visible outside of this function [-Wvisibility]". diff --git a/support/ebpf/ruby_tracer.ebpf.c b/support/ebpf/ruby_tracer.ebpf.c index 7acb6eac5..f19e2fb12 100644 --- a/support/ebpf/ruby_tracer.ebpf.c +++ b/support/ebpf/ruby_tracer.ebpf.c @@ -18,7 +18,7 @@ struct ruby_procs_t { // we start running out of instructions in the walk_ruby_stack program, one // option is to adjust this number downwards. // NOTE: the maximum size stack is FRAMES_PER_WALK_RUBY_STACK * calls to tail_call(). -#define FRAMES_PER_WALK_RUBY_STACK 32 +#define FRAMES_PER_WALK_RUBY_STACK 240 // When resolving a CME, we need to traverse environment pointers until we // find IMEMO_MENT. Since we can't do a while loop, we have to bound this // the max encountered in experimentation on a production rails app is 6. diff --git a/support/ebpf/system_config.ebpf.c b/support/ebpf/system_config.ebpf.c index d29d8c662..7d81e8169 100644 --- a/support/ebpf/system_config.ebpf.c +++ b/support/ebpf/system_config.ebpf.c @@ -33,15 +33,15 @@ int read_kernel_memory(UNUSED void *ctx) return 0; } - // Mark request handled - sys->pid = 0; - // Handle the read request - if (bpf_probe_read_kernel(sys->code, sizeof(sys->code), (void *)sys->address)) { - DEBUG_PRINT("Failed to read code from 0x%lx", (unsigned long)sys->address); - return -1; + sys->err = bpf_probe_read_kernel(sys->code, sizeof(sys->code), (void *)sys->address); + if (sys->err) { + DEBUG_PRINT("Failed to read code from 0x%lx: %ld", (unsigned long)sys->address, (long)sys->err); } + // Mark request handled once the helper has finished populating the result. + sys->pid = 0; + return 0; } @@ -65,9 +65,6 @@ int read_task_struct(struct bpf_raw_tracepoint_args *ctx) return 0; } - // Mark request handled - sys->pid = 0; - // Request to read current task. Adjust read address, and return // also the address of struct pt_regs in the entry stack. u64 addr = bpf_get_current_task() + sys->address; @@ -78,11 +75,14 @@ int read_task_struct(struct bpf_raw_tracepoint_args *ctx) sys->address = (u64)regs; // Execute the read request. - if (bpf_probe_read_kernel(sys->code, sizeof(sys->code), (void *)addr)) { - DEBUG_PRINT("Failed to read task_struct from 0x%lx", (unsigned long)addr); - return -1; + sys->err = bpf_probe_read_kernel(sys->code, sizeof(sys->code), (void *)addr); + if (sys->err) { + DEBUG_PRINT("Failed to read task_struct from 0x%lx: %ld", (unsigned long)addr, (long)sys->err); } + // Mark request handled once the helper has finished populating the result. + sys->pid = 0; + return 0; } diff --git a/support/ebpf/tracemgmt.h b/support/ebpf/tracemgmt.h index 8ac15130b..40e1b9c69 100644 --- a/support/ebpf/tracemgmt.h +++ b/support/ebpf/tracemgmt.h @@ -53,8 +53,7 @@ static inline EBPF_INLINE void increment_metric(u32 metricID) } // Send immediate notifications for event triggers to Go. -// Notifications for GENERIC_PID and RELOAD_KALLSYMS will be -// automatically inhibited until HA resets the type. +// Notifications for GENERIC_PID will be automatically inhibited until HA resets the type. static inline EBPF_INLINE void event_send_trigger(struct pt_regs *ctx, u32 event_type) { int inhibit_key = event_type; @@ -610,6 +609,8 @@ copy_state_regs(UnwindState *state, struct pt_regs *regs, bool interrupted_kerne state->sp = regs->sp; state->fp = regs->bp; state->rax = regs->ax; + state->rdi = regs->di; + state->r8 = regs->r8; state->r9 = regs->r9; state->r11 = regs->r11; state->r13 = regs->r13; diff --git a/support/ebpf/tracer.ebpf.amd64 b/support/ebpf/tracer.ebpf.amd64 index cda39d181..631f4ef7c 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 512510e3a..89e4c382c 100644 Binary files a/support/ebpf/tracer.ebpf.arm64 and b/support/ebpf/tracer.ebpf.arm64 differ diff --git a/support/ebpf/types.h b/support/ebpf/types.h index 574739e0a..d5ea103f5 100644 --- a/support/ebpf/types.h +++ b/support/ebpf/types.h @@ -358,6 +358,7 @@ typedef enum TracePrograms { PROG_UNWIND_DOTNET10, PROG_GO_LABELS, PROG_UNWIND_BEAM, + PROG_UNWIND_LUAJIT, NUM_TRACER_PROGS, } TracePrograms; @@ -663,7 +664,7 @@ typedef struct UnwindState { // The per-CPU registers which are not unwound, but needed to be accessed // on leaf frames. #if defined(__x86_64__) - u64 rax, r9, r11, r13, r15; + u64 rax, rdi, r8, r9, r11, r13, r15; #elif defined(__aarch64__) u64 r20, r22, r28; #endif @@ -877,19 +878,23 @@ typedef struct UnwindInfo { #define UNWIND_REG_LR 5 #define UNWIND_REG_X86_RAX 6 -#define UNWIND_REG_X86_R9 7 -#define UNWIND_REG_X86_R11 8 -#define UNWIND_REG_X86_R13 9 -#define UNWIND_REG_X86_R15 10 +#define UNWIND_REG_X86_RDI 7 +#define UNWIND_REG_X86_R8 8 +#define UNWIND_REG_X86_R9 9 +#define UNWIND_REG_X86_R11 10 +#define UNWIND_REG_X86_R13 11 +#define UNWIND_REG_X86_R15 12 // Flag to indicate a command (used inside Go stack delta generation only) -#define UNWIND_FLAG_COMMAND (1 << 0) +#define UNWIND_FLAG_COMMAND (1 << 0) // Flag to indicate that a full LR+FR frame is present on aarch64 -#define UNWIND_FLAG_FRAME (1 << 1) +#define UNWIND_FLAG_FRAME (1 << 1) // Flag to indicate that unwinding is valid on leaf frames only (uses untracked register) -#define UNWIND_FLAG_LEAF_ONLY (1 << 2) +#define UNWIND_FLAG_LEAF_ONLY (1 << 2) // Flag to indicate that the resolve CFA value should be dereferenced -#define UNWIND_FLAG_DEREF_CFA (1 << 3) +#define UNWIND_FLAG_DEREF_CFA (1 << 3) +// Flag to indicate that the return address is in a register +#define UNWIND_FLAG_REGISTER_RA (1 << 4) // If flags has UNWIND_FLAG_DEREF_CFA set, the lowest bits of 'param' are used // as second adder as post-deref operation. This contains the mask for that. @@ -969,6 +974,7 @@ typedef struct OffsetRange { typedef struct SystemAnalysis { u64 address; u32 pid; + s32 err; u8 code[128]; } SystemAnalysis; @@ -979,8 +985,7 @@ typedef struct Event { } Event; // Event types that notifications are sent for through event_send_trigger. -#define EVENT_TYPE_GENERIC_PID 1 -#define EVENT_TYPE_RELOAD_KALLSYMS 2 +#define EVENT_TYPE_GENERIC_PID 1 // PIDPage represents the key of the eBPF map pid_page_to_mapping_info. typedef struct PIDPage { diff --git a/support/ebpf/v8_tracer.ebpf.c b/support/ebpf/v8_tracer.ebpf.c index ee248a55a..61952dfad 100644 --- a/support/ebpf/v8_tracer.ebpf.c +++ b/support/ebpf/v8_tracer.ebpf.c @@ -14,7 +14,7 @@ #include "types.h" // The number of V8 frames to unwind per frame-unwinding eBPF program. -#define V8_FRAMES_PER_PROGRAM 8 +#define V8_FRAMES_PER_PROGRAM 60 // The maximum V8 frame length used in heuristic to validate FP #define V8_MAX_FRAME_LENGTH 8192 diff --git a/support/types.go b/support/types.go index 004e1ab8b..b982a1130 100644 --- a/support/types.go +++ b/support/types.go @@ -22,6 +22,7 @@ const ( FrameMarkerPerl = 0x7 FrameMarkerV8 = 0x8 FrameMarkerDotnet = 0xa + FrameMarkerLuaJIT = 0xd FrameMarkerBEAM = 0xc FrameMarkerGo = 0xb ) @@ -45,6 +46,7 @@ const ( ProgUnwindDotnet10 = 0x9 ProgGoLabels = 0xa ProgUnwindBEAM = 0xb + ProgUnwindLuaJIT = 0xc ) const ( @@ -54,8 +56,7 @@ const ( ) const ( - EventTypeGenericPID = 0x1 - EventTypeReloadKallsyms = 0x2 + EventTypeGenericPID = 0x1 ) const UnwindInfoMaxEntries = 0x4000 @@ -138,10 +139,10 @@ type StackDeltaPageKey struct { Page uint64 } type SystemAnalysis struct { - Address uint64 - Pid uint32 - Code [128]uint8 - Pad_cgo_0 [4]byte + Address uint64 + Pid uint32 + Err int32 + Code [128]uint8 } type TSDInfo struct { Offset int16 @@ -345,14 +346,18 @@ const ( UnwindRegFp uint8 = 0x4 UnwindRegLr uint8 = 0x5 UnwindRegX86RAX uint8 = 0x6 - UnwindRegX86R9 uint8 = 0x7 - UnwindRegX86R11 uint8 = 0x8 - UnwindRegX86R15 uint8 = 0xa + UnwindRegX86R9 uint8 = 0x9 + UnwindRegX86R11 uint8 = 0xa + UnwindRegX86R13 uint8 = 0xb + UnwindRegX86R15 uint8 = 0xc + UnwindRegX86RDI uint8 = 0x7 + UnwindRegX86R8 uint8 = 0x8 - UnwindFlagCommand uint8 = 0x1 - UnwindFlagFrame uint8 = 0x2 - UnwindFlagLeafOnly uint8 = 0x4 - UnwindFlagDerefCfa uint8 = 0x8 + UnwindFlagCommand uint8 = 0x1 + UnwindFlagFrame uint8 = 0x2 + UnwindFlagLeafOnly uint8 = 0x4 + UnwindFlagDerefCfa uint8 = 0x8 + UnwindFlagRegisterRA uint8 = 0x10 UnwindCommandInvalid int32 = 0x0 UnwindCommandStop int32 = 0x1 diff --git a/support/types_def.go b/support/types_def.go index 6c05aac10..3db048866 100644 --- a/support/types_def.go +++ b/support/types_def.go @@ -28,6 +28,7 @@ const ( FrameMarkerPerl = C.FRAME_MARKER_PERL FrameMarkerV8 = C.FRAME_MARKER_V8 FrameMarkerDotnet = C.FRAME_MARKER_DOTNET + FrameMarkerLuaJIT = C.FRAME_MARKER_LUAJIT FrameMarkerBEAM = C.FRAME_MARKER_BEAM FrameMarkerGo = C.FRAME_MARKER_GO ) @@ -51,6 +52,7 @@ const ( ProgUnwindDotnet10 = C.PROG_UNWIND_DOTNET10 ProgGoLabels = C.PROG_GO_LABELS ProgUnwindBEAM = C.PROG_UNWIND_BEAM + ProgUnwindLuaJIT = C.PROG_UNWIND_LUAJIT ) const ( @@ -60,8 +62,7 @@ const ( ) const ( - EventTypeGenericPID = C.EVENT_TYPE_GENERIC_PID - EventTypeReloadKallsyms = C.EVENT_TYPE_RELOAD_KALLSYMS + EventTypeGenericPID = C.EVENT_TYPE_GENERIC_PID ) const UnwindInfoMaxEntries = C.UNWIND_INFO_MAX_ENTRIES @@ -152,13 +153,17 @@ const ( UnwindRegX86RAX uint8 = C.UNWIND_REG_X86_RAX UnwindRegX86R9 uint8 = C.UNWIND_REG_X86_R9 UnwindRegX86R11 uint8 = C.UNWIND_REG_X86_R11 + UnwindRegX86R13 uint8 = C.UNWIND_REG_X86_R13 UnwindRegX86R15 uint8 = C.UNWIND_REG_X86_R15 + UnwindRegX86RDI uint8 = C.UNWIND_REG_X86_RDI + UnwindRegX86R8 uint8 = C.UNWIND_REG_X86_R8 // UnwindFlag values from the C header file - UnwindFlagCommand uint8 = C.UNWIND_FLAG_COMMAND - UnwindFlagFrame uint8 = C.UNWIND_FLAG_FRAME - UnwindFlagLeafOnly uint8 = C.UNWIND_FLAG_LEAF_ONLY - UnwindFlagDerefCfa uint8 = C.UNWIND_FLAG_DEREF_CFA + UnwindFlagCommand uint8 = C.UNWIND_FLAG_COMMAND + UnwindFlagFrame uint8 = C.UNWIND_FLAG_FRAME + UnwindFlagLeafOnly uint8 = C.UNWIND_FLAG_LEAF_ONLY + UnwindFlagDerefCfa uint8 = C.UNWIND_FLAG_DEREF_CFA + UnwindFlagRegisterRA uint8 = C.UNWIND_FLAG_REGISTER_RA // UnwindCommands from the C header file UnwindCommandInvalid int32 = C.UNWIND_COMMAND_INVALID diff --git a/tools/coredump/ebpfmaps.go b/tools/coredump/ebpfmaps.go index db9b83709..db5070665 100644 --- a/tools/coredump/ebpfmaps.go +++ b/tools/coredump/ebpfmaps.go @@ -234,9 +234,9 @@ func (emc *ebpfMapsCoredump) UpdatePidPageMappingInfo(pid libpf.PID, prefix lpm. host.FileID(fileID), bias) } -func (emc *ebpfMapsCoredump) DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (int, +func (emc *ebpfMapsCoredump) DeletePidPageMappingInfo(pid libpf.PID, prefixes []lpm.Prefix) (uint64, error) { - var deleted int + var deleted uint64 for _, prefix := range prefixes { if err := emc.DeletePidInterpreterMapping(pid, prefix); err != nil { return deleted, err diff --git a/tools/coredump/testdata/amd64/dotnet10-alpine3.23.json b/tools/coredump/testdata/amd64/dotnet10-alpine3.23.json index c8e0f4105..03172a019 100644 --- a/tools/coredump/testdata/amd64/dotnet10-alpine3.23.json +++ b/tools/coredump/testdata/amd64/dotnet10-alpine3.23.json @@ -49,7 +49,7 @@ "ld-musl-x86_64.so.1+0x6799f", "ld-musl-x86_64.so.1+0x6731a", "ld-musl-x86_64.so.1+0x6757a", - "" + "ld-musl-x86_64.so.1+0x68ec0" ] }, { diff --git a/tools/coredump/testdata/amd64/vfork-unwind.json b/tools/coredump/testdata/amd64/vfork-unwind.json new file mode 100644 index 000000000..271b23f0e --- /dev/null +++ b/tools/coredump/testdata/amd64/vfork-unwind.json @@ -0,0 +1,33 @@ +{ + "coredump-ref": "8f5e743313c1d20f0636ae821e7f4d2fb3b720b2956711edca5d45bf48a13a82", + "threads": [ + { + "lwp": 95340, + "frames": [ + "libc.so.6+0xeca7a", + "libc.so.6+0xf9a26", + "libc.so.6+0x10ec92", + "vfork+0x12a1", + "vfork+0x12eb", + "vfork+0x114e", + "libc.so.6+0x2a1c9", + "libc.so.6+0x2a28a", + "vfork+0x1184" + ] + } + ], + "modules": [ + { + "ref": "bb3ea285bd3612ccf0642d06b89783e2d73ce7d4db33f88f62235cf8a61dc771", + "local-path": "/home/hanshal101/mg/opentelemetry-ebpf-profiler/vfork" + }, + { + "ref": "d8db8739a1633c972cec6a4fe0566bdcec6fd088f98723492ab0361f66238f75", + "local-path": "/usr/lib/x86_64-linux-gnu/libc.so.6" + }, + { + "ref": "1cd555ac46b7887edeaf3c42aac5408c8135e52f6b37870da2cf82d5fe14e829", + "local-path": "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" + } + ] +} diff --git a/tools/coredump/testdata/arm64/java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h.json b/tools/coredump/testdata/arm64/java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h.json index 280f569b1..7da83f55f 100644 --- a/tools/coredump/testdata/arm64/java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h.json +++ b/tools/coredump/testdata/arm64/java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h.json @@ -40,7 +40,10 @@ "libjvm.so+0xbfe27b", "libjvm.so+0xe59ff7", "libjvm.so+0xe5a08f", - "" + "libjvm.so+0xdc3dcb", + "libjvm.so+0xb56fbb", + "libc.so.6+0x7edd7", + "libc.so.6+0xe7e5b" ] }, { @@ -66,7 +69,10 @@ "libjvm.so+0xbfe27b", "libjvm.so+0xe59ff7", "libjvm.so+0xe5a08f", - "" + "libjvm.so+0xdc3dcb", + "libjvm.so+0xb56fbb", + "libc.so.6+0x7edd7", + "libc.so.6+0xe7e5b" ] }, { diff --git a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.add-sp-sp.377026.json b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.add-sp-sp.377026.json index f74cda937..ee09766fe 100644 --- a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.add-sp-sp.377026.json +++ b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.add-sp-sp.377026.json @@ -121,7 +121,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -148,7 +151,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ldp-x29-x30.376761.json b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ldp-x29-x30.376761.json index 638dd7552..f184daa81 100644 --- a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ldp-x29-x30.376761.json +++ b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ldp-x29-x30.376761.json @@ -55,7 +55,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -262,7 +265,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ret.377192.json b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ret.377192.json index 2ed5dbbd4..2781725c7 100644 --- a/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ret.377192.json +++ b/tools/coredump/testdata/arm64/java.PrologueEpilogue.epi.ret.377192.json @@ -62,7 +62,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -173,7 +176,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/java.PrologueEpilogue.stp-fp-lr.json b/tools/coredump/testdata/arm64/java.PrologueEpilogue.stp-fp-lr.json index eedcad390..0e43c3626 100644 --- a/tools/coredump/testdata/arm64/java.PrologueEpilogue.stp-fp-lr.json +++ b/tools/coredump/testdata/arm64/java.PrologueEpilogue.stp-fp-lr.json @@ -63,7 +63,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -116,7 +119,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/java.PrologueEpilogue.sub-sp-sp.json b/tools/coredump/testdata/arm64/java.PrologueEpilogue.sub-sp-sp.json index 493d67905..c95240b56 100644 --- a/tools/coredump/testdata/arm64/java.PrologueEpilogue.sub-sp-sp.json +++ b/tools/coredump/testdata/arm64/java.PrologueEpilogue.sub-sp-sp.json @@ -26,7 +26,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -156,7 +159,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/java.VdsoPressure.osJavaTimeNanos.649996.json b/tools/coredump/testdata/arm64/java.VdsoPressure.osJavaTimeNanos.649996.json index 9fd1d2fd5..f8709f910 100644 --- a/tools/coredump/testdata/arm64/java.VdsoPressure.osJavaTimeNanos.649996.json +++ b/tools/coredump/testdata/arm64/java.VdsoPressure.osJavaTimeNanos.649996.json @@ -127,7 +127,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { @@ -286,7 +289,10 @@ "libjvm.so+0xc09c1b", "libjvm.so+0xe597f7", "libjvm.so+0xe5988f", - "" + "libjvm.so+0xdc5633", + "libjvm.so+0xb63fbb", + "libpthread-2.33.so+0x6f3b", + "libc-2.33.so+0xd2cdb" ] }, { diff --git a/tools/coredump/testdata/arm64/ruby-3.3.9-loop-with-ractors.json b/tools/coredump/testdata/arm64/ruby-3.3.9-loop-with-ractors.json index da94fd706..2bf952133 100644 --- a/tools/coredump/testdata/arm64/ruby-3.3.9-loop-with-ractors.json +++ b/tools/coredump/testdata/arm64/ruby-3.3.9-loop-with-ractors.json @@ -49,7 +49,7 @@ "libruby.so.3.3.9+0x2ac5cf", "libruby.so.3.3.9+0x2aca0b", "libruby.so.3.3.9+0x2ac8e7", - "" + "" ] }, { diff --git a/tools/coredump/testdata/arm64/ruby-3.4.5-loop-with-ractors.json b/tools/coredump/testdata/arm64/ruby-3.4.5-loop-with-ractors.json index 21fc2919f..f7b27f3eb 100644 --- a/tools/coredump/testdata/arm64/ruby-3.4.5-loop-with-ractors.json +++ b/tools/coredump/testdata/arm64/ruby-3.4.5-loop-with-ractors.json @@ -53,7 +53,7 @@ "libruby.so.3.4.5+0x2ce9f7", "libruby.so.3.4.5+0x2cefbf", "libruby.so.3.4.5+0x2cee9f", - "" + "" ] }, { diff --git a/tools/coredump/testdata/arm64/ruby-3.5.0-loop-with-ractors.json b/tools/coredump/testdata/arm64/ruby-3.5.0-loop-with-ractors.json index 3d78bc8ea..073508ac8 100644 --- a/tools/coredump/testdata/arm64/ruby-3.5.0-loop-with-ractors.json +++ b/tools/coredump/testdata/arm64/ruby-3.5.0-loop-with-ractors.json @@ -50,7 +50,7 @@ "libruby.so.3.5.0+0x2c6a47", "libruby.so.3.5.0+0x2c700b", "libruby.so.3.5.0+0x2c6eeb", - "" + "" ] }, { diff --git a/tools/coredump/testsources/c/vfork.c b/tools/coredump/testsources/c/vfork.c new file mode 100644 index 000000000..46707bed9 --- /dev/null +++ b/tools/coredump/testsources/c/vfork.c @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Example application that uses vfork() to test unwinding from the child +// process. +// +// cc -O2 -g -o vfork vfork.c + +#include +#include +#include +#include +#include +#include + +void child_func() { + // Allow any process to ptrace us (needed for gcore in some environments) + prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); + + printf("Child: PID %d, Parent PID %d. Waiting for signal...\n", getpid(), + getppid()); + // Wait for gcore to capture us. + while (1) { + sleep(1); + } +} + +void parent_func() { + pid_t pid = vfork(); + if (pid == 0) { + // Child process + child_func(); + _exit(0); + } else if (pid > 0) { + // Parent process + // Note: Parent is BLOCKED here until child _exits or execs. + // So if child loops, parent stays here. + printf("Parent: Child PID %d finished\n", pid); + } else { + perror("vfork"); + } +} + +int main() { + parent_func(); + return 0; +} diff --git a/tools/probe-ctrl/go.mod b/tools/probe-ctrl/go.mod index 52ecb1622..5326eeb13 100644 --- a/tools/probe-ctrl/go.mod +++ b/tools/probe-ctrl/go.mod @@ -11,7 +11,7 @@ replace go.opentelemetry.io/ebpf-profiler => ../../ require ( github.com/cilium/ebpf v0.21.0 - go.opentelemetry.io/ebpf-profiler v0.0.202614 + go.opentelemetry.io/ebpf-profiler v0.0.202618 ) require ( @@ -32,11 +32,11 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/zeebo/xxh3 v1.1.0 // indirect - go.opentelemetry.io/collector/consumer v1.56.0 // indirect - go.opentelemetry.io/collector/consumer/xconsumer v0.150.0 // indirect - go.opentelemetry.io/collector/featuregate v1.56.0 // indirect - go.opentelemetry.io/collector/pdata v1.56.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.150.0 // indirect + go.opentelemetry.io/collector/consumer v1.57.0 // indirect + go.opentelemetry.io/collector/consumer/xconsumer v0.151.0 // indirect + go.opentelemetry.io/collector/featuregate v1.57.0 // indirect + go.opentelemetry.io/collector/pdata v1.57.0 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.151.0 // indirect go.opentelemetry.io/otel v1.43.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect @@ -53,7 +53,7 @@ require ( golang.org/x/tools v0.44.0 // indirect golang.org/x/vuln v1.3.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect - google.golang.org/grpc v1.80.0 // indirect + google.golang.org/grpc v1.81.0 // indirect google.golang.org/protobuf v1.36.11 // indirect honnef.co/go/tools v0.7.0 // indirect ) diff --git a/tools/probe-ctrl/go.sum b/tools/probe-ctrl/go.sum index 3be97d45d..bf4b113d5 100644 --- a/tools/probe-ctrl/go.sum +++ b/tools/probe-ctrl/go.sum @@ -67,8 +67,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260422152846-dd95db7b8093 h1:NWkokqNTFElJQUa1VLnW/8RVL0JTGyNdGtfiRpUBBcs= -github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260422152846-dd95db7b8093/go.mod h1:WPdgk1BinVdvYdkbt1KIkgDw6qUiK8CnGq+ftaJ41Ns= +github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260504053944-5ab2ab77ce06 h1:G6x0sl7jhDrYYSkX8Gj6KyAeoqU78oQfGD0v8qWcVDQ= +github.com/open-telemetry/sig-profiling/profcheck v0.0.0-20260504053944-5ab2ab77ce06/go.mod h1:WPdgk1BinVdvYdkbt1KIkgDw6qUiK8CnGq+ftaJ41Ns= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -84,18 +84,18 @@ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/collector/consumer v1.56.0 h1:olhuaTI3cic6VfcraXt3qqsv1v4Qxf55gHxOO1uIVXw= -go.opentelemetry.io/collector/consumer v1.56.0/go.mod h1:FpnfeTLQAdcOtzrkQ36Z+E5aconIymkv9xpJuAdLvy0= -go.opentelemetry.io/collector/consumer/xconsumer v0.150.0 h1:URO73bAV00wTH9bJeloqaiLgS3Q80GNci+nm1iZ3W6Q= -go.opentelemetry.io/collector/consumer/xconsumer v0.150.0/go.mod h1:BMcOInfcRUpVZ2R4qa3vNglvU6mWL+0dhAayH87YSB8= -go.opentelemetry.io/collector/featuregate v1.56.0 h1:NjcbOZkdCSXddAJmFLdO+pv1gmAgrU6sC5PBga2KlKI= -go.opentelemetry.io/collector/featuregate v1.56.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= -go.opentelemetry.io/collector/internal/testutil v0.150.0 h1:J4PLQGPfbLVaL5eI1aMc0m0TMixV9wzBhNhoHU00J0I= -go.opentelemetry.io/collector/internal/testutil v0.150.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= -go.opentelemetry.io/collector/pdata v1.56.0 h1:W+QAfN2Iz8SNss1T5JNzRWFnw+7oP1vXBQH9ZuOJkXY= -go.opentelemetry.io/collector/pdata v1.56.0/go.mod h1:usR9utboXufbD1rp1oJy+3smQXXpZ+CsI3WN7QsiOs0= -go.opentelemetry.io/collector/pdata/pprofile v0.150.0 h1:Ae+FxmYXDdcqeLqIAdNSO3YGxco7RS2mIMTdjvavfso= -go.opentelemetry.io/collector/pdata/pprofile v0.150.0/go.mod h1:tEBeGysY/LpIh39NLoQQl3qmUBOF9wyH5p/fmn7smzM= +go.opentelemetry.io/collector/consumer v1.57.0 h1:jyDh4GkYPuIXNB0UJIh33NAzZoTCVNkwS+XWdlI08P8= +go.opentelemetry.io/collector/consumer v1.57.0/go.mod h1:tJKbog9Xw/8y66aWd/C+21BMuQkOWn/lF4bzJDRC9OM= +go.opentelemetry.io/collector/consumer/xconsumer v0.151.0 h1:eKIYxuPBEIrjZMAkyKBUWrlpHAE9OgxXBjq7PMSeXkE= +go.opentelemetry.io/collector/consumer/xconsumer v0.151.0/go.mod h1:9K97TkCN7XYfwKzPzktozrWc3Qw/4A1T4XgMn9TnG0c= +go.opentelemetry.io/collector/featuregate v1.57.0 h1:KPDSUKYn6MHwgyGRSGPPcW/G96HH93pxuvvPwM+R8nY= +go.opentelemetry.io/collector/featuregate v1.57.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU= +go.opentelemetry.io/collector/internal/testutil v0.151.0 h1:CFjDItLuqzblItOsnK6IPSdrsOaZCaDjYpB8qWG+XHI= +go.opentelemetry.io/collector/internal/testutil v0.151.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= +go.opentelemetry.io/collector/pdata v1.57.0 h1:oDWBMjEIqyJO3GJEB+iwqxj47rxDK19OKzwaFEaE4sg= +go.opentelemetry.io/collector/pdata v1.57.0/go.mod h1:wZojinP6mNhLXudH8QXx/bjWzOsKMxi/FXwnk+12G/w= +go.opentelemetry.io/collector/pdata/pprofile v0.151.0 h1:hsU0+DpkvhJh3xL1Y8CX2vAPdLMoJLiw+C+rAMsaxZc= +go.opentelemetry.io/collector/pdata/pprofile v0.151.0/go.mod h1:5zfGTQqRuaKyh2SRaZi4SV4nSD8TzY1kYoOjniOD3uk= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= @@ -163,8 +163,8 @@ gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/tools/stackdeltas/stackdeltas.go b/tools/stackdeltas/stackdeltas.go index 8ab23e278..cfedfc3a7 100644 --- a/tools/stackdeltas/stackdeltas.go +++ b/tools/stackdeltas/stackdeltas.go @@ -80,15 +80,21 @@ func getOpcode(baseReg uint8, param int32, deref bool) string { } func dumpDelta(delta sdtypes.StackDelta, merged bool) { - var cfa, fp string + var cfa, aux string info := &delta.Info if info.Flags&support.UnwindFlagCommand != 0 { cfa = getCommand(info.Param) } else { cfa = getOpcode(info.BaseReg, info.Param, info.Flags&support.UnwindFlagDerefCfa != 0) - fp = getOpcode(info.AuxBaseReg, info.AuxParam, false) + aux = getOpcode(info.AuxBaseReg, info.AuxParam, false) } comment := "" + if info.Flags&support.UnwindFlagRegisterRA != 0 { + comment += " ra-reg" + } + if info.Flags&support.UnwindFlagLeafOnly != 0 { + comment += " leaf-only" + } if delta.Hints&sdtypes.UnwindHintKeep != 0 { comment += " keep" } @@ -98,7 +104,7 @@ func dumpDelta(delta sdtypes.StackDelta, merged bool) { if merged { comment += " merged" } - fmt.Printf("%016x %-16s%-16s%s\n", delta.Address, cfa, fp, comment) + fmt.Printf("%016x %-16s%-16s%s\n", delta.Address, cfa, aux, comment) } func canMerge(delta, nextDelta sdtypes.StackDelta) bool { diff --git a/tracer/events.go b/tracer/events.go index 9cd8cf6ea..d2e365daa 100644 --- a/tracer/events.go +++ b/tracer/events.go @@ -82,9 +82,6 @@ func (t *Tracer) triggerReportEvent(data []byte) { switch event.Type { case support.EventTypeGenericPID: t.handleGenericPID() - case support.EventTypeReloadKallsyms: - t.enableEvent(support.EventTypeReloadKallsyms) - t.kernelSymbolizer.Reload() } } diff --git a/tracer/helper.go b/tracer/helper.go index 75bfef12a..ca75aec37 100644 --- a/tracer/helper.go +++ b/tracer/helper.go @@ -50,7 +50,7 @@ func hasProbeReadBug(major, minor, patch uint32) bool { } // getOnlineCPUIDs reads online CPUs from /sys/devices/system/cpu/online and reports -// the core IDs as a list of integers. +// the core IDs as a list of integers. You should probably use `onlineCPUsOnce` instead. func getOnlineCPUIDs() ([]int, error) { cpuPath := "/sys/devices/system/cpu/online" buf, err := os.ReadFile(cpuPath) diff --git a/tracer/systemconfig.go b/tracer/systemconfig.go index 51781dd6a..43646123e 100644 --- a/tracer/systemconfig.go +++ b/tracer/systemconfig.go @@ -10,6 +10,7 @@ import ( "os" "runtime" "strings" + "syscall" "unsafe" "go.opentelemetry.io/ebpf-profiler/kallsyms" @@ -32,6 +33,11 @@ type sysConfigVars struct { stack_ptregs_offset uint32 } +var ( + errSystemAnalysisNotHandled = errors.New("system analysis request was not handled") + errSystemAnalysisFailed = errors.New("system analysis helper failed") +) + // memberByName resolves btf Member from a Struct with given name func memberByName(t *btf.Struct, field string) (*btf.Member, error) { for i, m := range t.Members { @@ -163,10 +169,29 @@ func executeSystemAnalysisBpfCode(progSpec *cebpf.ProgramSpec, maps map[string]* if err != nil { return nil, 0, fmt.Errorf("failed to get analysis data: %v", err) } + if err = validateSystemAnalysisResult(data, address); err != nil { + return nil, 0, err + } return data.Code[:], data.Address, nil } +func validateSystemAnalysisResult(data support.SystemAnalysis, address libpf.SymbolValue) error { + if data.Pid != 0 { + return fmt.Errorf("%w for pid %d at 0x%x", errSystemAnalysisNotHandled, data.Pid, address) + } + + if data.Err != 0 { + if data.Err < 0 { + return fmt.Errorf("%w at 0x%x: %w (helper err=%d)", errSystemAnalysisFailed, address, syscall.Errno(-data.Err), data.Err) + } + + return fmt.Errorf("%w at 0x%x: helper err=%d", errSystemAnalysisFailed, address, data.Err) + } + + return nil +} + // loadKernelCode will request the ebpf code to read the first X bytes from given address. func loadKernelCode(coll *cebpf.CollectionSpec, maps map[string]*cebpf.Map, address libpf.SymbolValue, @@ -242,6 +267,9 @@ func prepareAnalysis(orig *cebpf.CollectionSpec) (*cebpf.CollectionSpec, map[str } new.Maps["system_analysis"] = orig.Maps["system_analysis"].Copy() new.Maps[".rodata.var"] = orig.Maps[".rodata.var"].Copy() + if rodata, ok := orig.Maps[".rodata"]; ok { + new.Maps[".rodata"] = rodata.Copy() + } new.Programs["read_kernel_memory"] = orig.Programs["read_kernel_memory"].Copy() new.Programs["read_task_struct"] = orig.Programs["read_task_struct"].Copy() diff --git a/tracer/systemconfig_test.go b/tracer/systemconfig_test.go new file mode 100644 index 000000000..b11a35635 --- /dev/null +++ b/tracer/systemconfig_test.go @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package tracer + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/ebpf-profiler/libpf" + "go.opentelemetry.io/ebpf-profiler/support" +) + +func TestValidateSystemAnalysisResult(t *testing.T) { + address := libpf.SymbolValue(0x1234) + + t.Run("not handled", func(t *testing.T) { + err := validateSystemAnalysisResult(support.SystemAnalysis{Pid: 77}, address) + require.Error(t, err) + require.ErrorIs(t, err, errSystemAnalysisNotHandled) + require.ErrorContains(t, err, "pid 77") + }) + + t.Run("helper failure", func(t *testing.T) { + err := validateSystemAnalysisResult(support.SystemAnalysis{Err: -14}, address) + require.Error(t, err) + require.True(t, errors.Is(err, errSystemAnalysisFailed)) + require.ErrorContains(t, err, "helper err=-14") + }) + + t.Run("success", func(t *testing.T) { + err := validateSystemAnalysisResult(support.SystemAnalysis{}, address) + require.NoError(t, err) + }) +} diff --git a/tracer/tracer.go b/tracer/tracer.go index 3a9f09258..70e0dc11c 100644 --- a/tracer/tracer.go +++ b/tracer/tracer.go @@ -79,6 +79,9 @@ type Intervals interface { ExecutableUnloadDelay() time.Duration } +// onlineCPUs once resolves and caches the list of online CPUs. +var onlineCPUsOnce = sync.OnceValues(getOnlineCPUIDs) + // Tracer provides an interface for loading and initializing the eBPF components as // well as for monitoring the output maps for new traces and count updates. type Tracer struct { @@ -305,6 +308,7 @@ func (t *Tracer) Close() { } t.processManager.Close() + t.kernelSymbolizer.Close() t.signalDone() } @@ -492,10 +496,6 @@ func initializeMapsAndPrograms(kmod *kallsyms.Module, cfg *Config) ( } } - if err = loadKallsymsTrigger(coll, ebpfProgs, cfg.BPFVerifierLogLevel); err != nil { - return nil, nil, nil, fmt.Errorf("failed to load kallsym eBPF program: %v", err) - } - if err = removeTemporaryMaps(ebpfMaps); err != nil { return nil, nil, nil, fmt.Errorf("failed to remove temporary maps: %v", err) } @@ -695,27 +695,6 @@ func loadAllMaps(coll *cebpf.CollectionSpec, cfg *Config, return nil } -// loadKallsymsTrigger loads the eBPF program that triggers kallsym updates. -func loadKallsymsTrigger(coll *cebpf.CollectionSpec, - ebpfProgs map[string]*cebpf.Program, bpfVerifierLogLevel uint32) error { - programOptions := cebpf.ProgramOptions{ - LogLevel: cebpf.LogLevel(bpfVerifierLogLevel), - } - - kallsymsTriggerProg := "kprobe__kallsyms" - progSpec, ok := coll.Programs[kallsymsTriggerProg] - if !ok { - return fmt.Errorf("program %s does not exist", kallsymsTriggerProg) - } - - if err := loadProgram(ebpfProgs, nil, 0, progSpec, - programOptions, true); err != nil { - return err - } - - return nil -} - // schedTimesSize calculates the size of the sched_times map based on the // configured off-cpu threshold. // To not lose too many scheduling events but also not oversize sched_times, @@ -904,7 +883,11 @@ func (t *Tracer) symbolizeKernelFrames(addrs []uint64, oldFrames libpf.Frames) l Type: libpf.KernelFrame, AddressOrLineno: libpf.AddressOrLineno(address - 1), } - if kmod, err := t.kernelSymbolizer.GetModuleByAddress(address); err == nil { + if funcName, offset, ok := t.kernelSymbolizer.LookupBPFSymbol(address); ok { + // BPF program: use address relative to symbol start for deduplication. + frame.AddressOrLineno = libpf.AddressOrLineno(offset) + frame.FunctionName = libpf.Intern(funcName) + } else if kmod, err := t.kernelSymbolizer.GetModuleByAddress(address); err == nil { frame.Mapping = kmod.Mapping() frame.AddressOrLineno -= libpf.AddressOrLineno(kmod.Start()) if funcName, _, err := kmod.LookupSymbolByAddress(address); err == nil { @@ -1092,7 +1075,12 @@ func (t *Tracer) loadBpfTrace(raw []byte, cpu int) (*libpf.EbpfTrace, error) { // StartMapMonitors starts goroutines for collecting metrics and monitoring eBPF // maps for tracepoints, new traces, trace count updates and unknown PCs. func (t *Tracer) StartMapMonitors(ctx context.Context, traceOutChan chan<- *libpf.EbpfTrace) error { - if err := t.kernelSymbolizer.StartMonitor(ctx); err != nil { + onlineCPUs, err := onlineCPUsOnce() + if err != nil { + return fmt.Errorf("failed to get online cpus: %w", err) + } + + if err := t.kernelSymbolizer.StartMonitor(ctx, onlineCPUs); err != nil { log.Warnf("Failed to start kallsyms monitor: %v", err) } eventMetricCollector, err := t.startEventMonitor(ctx) @@ -1142,33 +1130,6 @@ func (t *Tracer) StartMapMonitors(ctx context.Context, traceOutChan chan<- *libp return nil } -func (t *Tracer) attachToKallsymsUpdates() error { - prog, ok := t.ebpfProgs["kprobe__kallsyms"] - if !ok { - return fmt.Errorf("kprobe__kallsyms is not available") - } - - kallsymsAttachPoint := "bpf_ksym_add" - kmod, err := t.kernelSymbolizer.GetModuleByName(kallsyms.Kernel) - if err != nil { - return err - } - - if _, err := kmod.LookupSymbol(kallsymsAttachPoint); err != nil { - log.Infof("Monitoring kallsyms is supported only for Linux kernel 5.8 or greater: %s: %v", - kallsymsAttachPoint, err) - return nil - } - - hook, err := link.Kprobe(kallsymsAttachPoint, prog, nil) - if err != nil { - return fmt.Errorf("failed opening kprobe for kallsyms trigger: %s", err) - } - t.hooks[hookPoint{group: "kprobe", name: kallsymsAttachPoint}] = hook - - return nil -} - // terminatePerfEvents disables perf events and closes their file descriptor. func terminatePerfEvents(events []*perf.Event) { for _, event := range events { @@ -1196,14 +1157,14 @@ func (t *Tracer) AttachTracer() error { return fmt.Errorf("failed to configure software perf event: %v", err) } - onlineCPUIDs, err := getOnlineCPUIDs() + onlineCPUs, err := onlineCPUsOnce() if err != nil { - return fmt.Errorf("failed to get online CPUs: %v", err) + return fmt.Errorf("failed to get online cpus: %w", err) } events := t.perfEntrypoints.WLock() defer t.perfEntrypoints.WUnlock(&events) - for _, id := range onlineCPUIDs { + for _, id := range onlineCPUs { perfEvent, err := perf.Open(perfAttribute, perf.AllThreads, id, nil) if err != nil { terminatePerfEvents(*events) @@ -1216,11 +1177,6 @@ func (t *Tracer) AttachTracer() error { *events = append(*events, perfEvent) } - if err = t.attachToKallsymsUpdates(); err != nil { - terminatePerfEvents(*events) - return err - } - return nil } diff --git a/tracer/types/parse.go b/tracer/types/parse.go index 78621968a..d06cf7bd1 100644 --- a/tracer/types/parse.go +++ b/tracer/types/parse.go @@ -22,6 +22,7 @@ const ( RubyTracer V8Tracer DotnetTracer + LuaJITTracer GoTracer Labels BEAMTracer @@ -38,6 +39,7 @@ var tracerTypeToName = map[tracerType]string{ RubyTracer: "ruby", V8Tracer: "v8", DotnetTracer: "dotnet", + LuaJITTracer: "luajit", GoTracer: "go", Labels: "labels", BEAMTracer: "beam",