[
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: Bug Report\nabout: Template for bug reports\nlabels: kind/bug\n---\n\n# Expected Behavior\n\n# Actual Behavior\n\n# Steps to Reproduce the Problem\n\n1.\n2.\n3.\n\n# Additional Info\n\n- Kubernetes version:\n\n  **Output of `kubectl version`:**\n\n  ```\n  (paste your output here)\n  ```\n\n\n- operation-system/kernel version:\n  \n  **Output of `awk -F '=' '/PRETTY_NAME/ { print $2 }' /etc/os-release`:**\n  **Output of `uname -r`:**\n  ```\n  (paste your output here)\n  ```\n\n<!-- Any other additional information -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.md",
    "content": "---\nname: Feature Request\nabout: Template for feature requests\nlabels: kind/feature\n---\n\n### Feature request\n\n<!-- Please describe the feature request and why you would like to have it -->\n\n### Use case\n\n<!-- Please add a concrete use case to demonstrate how such a feature would add value for the user. If you don't have a use case for your feature, please remove this section (however providing a good use case increases the likelihood to be picked up) -->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "#### What type of this PR\nExamples of user facing changes:\n- API changes\n- Bug fixes\n<!-- \nDescribe your changes here- ideally you can get that description straight from your descriptive commit message(s)! \n\nIn addition, categorize the changes you're making using the \"/kind\" Prow command, example:\n\n/kind <kind>\n\nSupported kinds are: bug, cleanup, design, documentation, failing-test, feature, flake, misc, question, tep\n-->\n\n#### Which issue(s) this PR fixes:\nFixes #(issue-number)\n\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    tags:\n    - 'v*.*.*'\njobs:\n  docker:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Set env\n      id: vars\n      run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}\n    - name: Set up Docker Buildx\n      uses: docker/setup-buildx-action@v1\n    - name: Set up QEMU\n      uses: docker/setup-qemu-action@v2\n    - name: Login to DockerHub\n      uses: docker/login-action@v1 \n      with:\n        username: ${{ secrets.DOCKERHUB_USERNAME }}\n        password: ${{ secrets.DOCKERHUB_TOKEN }}\n    - name: Build and push\n      uses: docker/build-push-action@v2\n      with:\n        push: true\n        tags: keyval/otel-go-agent:${{ steps.vars.outputs.tag }}\n        platforms: linux/amd64,linux/arm64\n"
  },
  {
    "path": ".gitignore",
    "content": "**/bpf_bpfel.go\n**/bpf_bpfel.o\n/.idea/\nkv-go-instrumentation"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guide\n\n- [New Contributor Guide](#contributing-guide)\n  - [Ways to Contribute](#ways-to-contribute)\n  - [Find an Issue](#find-an-issue)\n  - [Ask for Help](#ask-for-help)\n  - [Pull Request Lifecycle](#pull-request-lifecycle)\n  - [Development Environment Setup](#development-environment-setup)\n  - [Sign Your Commits](#sign-your-commits)\n  - [Pull Request Checklist](#pull-request-checklist)\n\nWelcome! We are glad that you want to contribute to our project! 💖\n\nAs you get started, you are in the best position to give us feedback on areas of\nour project that we need help with including:\n\n- Problems found during setting up a new developer environment\n- Gaps in our Quickstart Guide or documentation\n- Bugs in our automation scripts\n\nIf anything doesn't make sense, or doesn't work when you run it, please open a\nbug report and let us know!\n\n## Ways to Contribute\n\nWe welcome many different types of contributions including:\n\n- New features\n- Builds, CI/CD\n- Bug fixes\n- Documentation\n- Issue Triage\n- Answering questions on Slack/Mailing List\n- Web design\n- Communications / Social Media / Blog Posts\n- Release management\n\n## Find an Issue\n\nWe have good first issues for new contributors and help wanted issues suitable\nfor any contributor. [good first issue](TODO) has extra information to\nhelp you make your first contribution. [help wanted](TODO) are issues\nsuitable for someone who isn't a core maintainer and is good to move onto after\nyour first pull request.\n\nSometimes there won’t be any issues with these labels. That’s ok! There is\nlikely still something for you to work on.\n\nOnce you see an issue that you'd like to work on, please post a comment saying\nthat you want to work on it. Something like \"I want to work on this\" is fine.\n\n## Ask for Help\n\nThe best way to reach us with a question when contributing is to ask on:\n\n- The original github issue\n- The developer mailing list\n- Our Slack channel\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM fedora:35 as builder\nARG TARGETARCH\nRUN dnf install clang llvm make libbpf-devel -y\nRUN curl -LO https://go.dev/dl/go1.18.linux-$TARGETARCH.tar.gz && tar -C /usr/local -xzf go*.linux-$TARGETARCH.tar.gz\nENV PATH=\"/usr/local/go/bin:${PATH}\"\nWORKDIR /app\nCOPY . .\nRUN TARGET=$TARGETARCH make build\n\nFROM registry.fedoraproject.org/fedora-minimal:35\nCOPY --from=builder /app/kv-go-instrumentation /\nCMD [\"/kv-go-instrumentation\"]"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "# Obtain an absolute path to the directory of the Makefile.\n# Assume the Makefile is in the root of the repository.\nREPODIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\n# Build the list of include directories to compile the bpf program\nBPF_INCLUDE += -I${REPODIR}/include/libbpf\nBPF_INCLUDE += -I${REPODIR}/include\n\n.PHONY: generate\ngenerate: export CFLAGS := $(BPF_INCLUDE)\ngenerate:\n\tgo mod tidy\n\tgo generate ./...\n\n.PHONY: build\nbuild: generate\n\tGOOS=linux go build -o kv-go-instrumentation cli/main.go\n\n.PHONY: docker-build\ndocker-build:\n\tdocker build -t $(IMG) ."
  },
  {
    "path": "README.md",
    "content": "# OpenTelemetry Auto-Instrumentation for Go\n\nThis project adds [OpenTelemetry instrumentation](https://opentelemetry.io/docs/concepts/instrumenting/#automatic-instrumentation)\nto Go applications without having to modify their source code.\nWe support a wide range of Go versions (1.12+) and even work on stripped binaries.\n\nOur goal is to provide the same level of automatic instrumentation for Go as exists for languages such as Java and Python.\n\nThis automatic instrumentation is based on [eBPF](https://ebpf.io/) uprobes.\n\nFor more information, see our [How it works](docs/how-it-works.md) document.\n\n## Getting Started\n\nCheck out our [Getting Started on Kubernetes](docs/getting-started/README.md) guide for easily instrumenting your first Go applications.\n\n## Current Instrumentations\n\n| Library/Framework |\n| ----------------- |\n| net/http - Server |\n| gRPC - Client     |\n| gRPC - Server     |\n| Gorilla Mux       |\n\n## Project Status\n\nThis project is actively maintained by [keyval](https://keyval.dev) and is currently in its initial days. We would love to receive your ideas, feedback & contributions.\n\n## Contributing\n\nPlease refer to the [contributing.md](CONTRIBUTING.md) file for information about how to get involved. We welcome issues, questions, and pull requests.\n\n## License\n\nThis project is licensed under the terms of the Apache 2.0 open source license. Please refer to [LICENSE](LICENSE) for the full terms.\n"
  },
  {
    "path": "cli/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/errors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/opentelemetry\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process\"\n)\n\nfunc main() {\n\terr := log.Init()\n\tif err != nil {\n\t\tfmt.Printf(\"could not init logger: %s\\n\", err)\n\t\tos.Exit(1)\n\t}\n\ttarget := process.ParseTargetArgs()\n\tif err = target.Validate(); err != nil {\n\t\tlog.Logger.Error(err, \"invalid target args\")\n\t\treturn\n\t}\n\tlog.Logger.V(0).Info(\"starting Go OpenTelemetry Agent ...\")\n\n\tprocessAnalyzer := process.NewAnalyzer()\n\tvar otelController *opentelemetry.Controller\n\n\tif target.Stdout {\n\t\totelController, err = opentelemetry.NewStdoutController()\n\t} else {\n\t\totelController, err = opentelemetry.NewController()\n\t}\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"unable to create OpenTelemetry controller\")\n\t\treturn\n\t}\n\n\tinstManager, err := instrumentors.NewManager(otelController)\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"error creating instrumetors manager\")\n\t\treturn\n\t}\n\n\tstopper := make(chan os.Signal, 1)\n\tsignal.Notify(stopper, os.Interrupt, syscall.SIGTERM)\n\tgo func() {\n\t\t<-stopper\n\t\tlog.Logger.V(0).Info(\"Got SIGTERM, cleaning up..\")\n\t\tprocessAnalyzer.Close()\n\t\tinstManager.Close()\n\t}()\n\n\tpid, err := processAnalyzer.DiscoverProcessID(target)\n\tif err != nil {\n\t\tif err != errors.ErrInterrupted {\n\t\t\tlog.Logger.Error(err, \"error while discovering process id\")\n\t\t}\n\t\treturn\n\t}\n\n\ttargetDetails, err := processAnalyzer.Analyze(pid, instManager.GetRelevantFuncs())\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"error while analyzing target process\")\n\t\treturn\n\t}\n\tlog.Logger.V(0).Info(\"target process analysis completed\", \"pid\", targetDetails.PID,\n\t\t\"go_version\", targetDetails.GoVersion, \"dependencies\", targetDetails.Libraries,\n\t\t\"total_functions_found\", len(targetDetails.Functions))\n\n\tinstManager.FilterUnusedInstrumentors(targetDetails)\n\n\tlog.Logger.V(0).Info(\"invoking instrumentors\")\n\terr = instManager.Run(targetDetails)\n\tif err != nil && err != errors.ErrInterrupted {\n\t\tlog.Logger.Error(err, \"error while running instrumentors\")\n\t}\n}\n"
  },
  {
    "path": "docs/design/context-propagation.md",
    "content": "# Design Proposal: Context Propagation\n\n## Motivation\n\nContext propagation is a mechanism that allows tracing to be propagated across process boundaries. Usually, propagation is done by passing traceId and spanId of the current span to the next process. Those identifiers are passed as headers over the requests and responses.\n\nThe examples in this proposal describes context propagation over HTTP/gRPC formatted as [W3C Trace Context](https://www.w3.org/TR/trace-context/). However, the implementation should support other transportation methods and header formats.\n\n## Overview\n\nThe context propagation implementation should support the following:\n\n1. **Reading headers**: If the current transaction is a part of an existing distributed trace, the request / response should contain headers according to the chosen format.\n2. **Storing the current span context**: data about the current span should be stored in an eBPF map to be used by the next process. The suggested data structure is a map from goroutine id to an object similar to [trace.SpanContext](https://pkg.go.dev/go.opentelemetry.io/otel/trace#SpanContext). The current span map should always hold the current running span. Entries can be written by one of the following:\n\n- Header propagator (the use case described in this document) - for remote spans created outside of the current process.\n- Automatic instrumentation - for spans created by the automatic instrumentation agent.\n- Manual instrumentation - for spans created manually by the user.\n\n3. **Writing headers**: the implementation should get the current span from the eBPF map and propagate it to the next process by adding new headers to the request / response.\n\nNotice that currently, the automatic instrumentation correlates spans to the same trace if they are being executed by the same goroutine. In the future we plan to implement a more robust tracking of the goroutine tree to support traces from multiple goroutines. As part of this planned change, the current implementation of context propagation will also have to be changed (different key in the current span map).\n\n## Example walkthrough\n\nIn order to better understand how all the different pieces fit together, we will walk through an example. The example is based on the following scenario:\n\n```mermaid\ngraph LR\n    A[Application A] -->|HTTP| B(Target Application)\n    B --->|HTTP| A\n    B -->|gRPC| C(Application B)\n    C --->|gRPC|B\n```\n\nThe target application is a simple HTTP server. For every request it receives, it sends a gRPC request to another application. The gRPC response is then sent back to the client. We assume that applications A and B are already instrumented.\n\n#### Step 1: Read request headers\n\nThe current HTTP server instrumentation is attached to the following function:\n\n```go\nfunc (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)\n```\n\nThe instrumentation is already reading fields from the `http.Request` object. Getting the headers should be a matter of tracking the `Header` field in [offsets-tracker](https://github.com/keyval-dev/offsets-tracker) and reading the values according to W3C Trace Context specification.\n\n#### Step 2: Store the headers as current span in the SpanContext map\n\nUpdate the SpanContext map with key equals to the current gorountine id and value equals to SpanContext object (traceId and spanId).\n\n#### Step 3: Create an HTTP span\n\nCurrent implementation of HTTP server instrumentor already creates a span for the request. The span traceId and parent spanId should be set according to the values in the eBPF map.\n\n#### Step 4: Update SpanContext map\n\nUpdate the map with the newly created HTTP span as the current span.\n\n#### Step 5: Add headers to gRPC request\n\nIn general, the context propagation implementation should attach a uprobe to a function that writes the headers to the outgoing request.\nFor example, in gRPC we may choose to attach a uprobe to the following function:\n\n```go\nfunc (l *loopyWriter) writeHeader(streamID uint32, endStream bool, hf []hpack.HeaderField, onWrite func()) error\n```\n\nThe context propagation implementation will use the kernel helper function `bpf_probe_write_user()` in order to modify the `hf` array according to the current span (taken from the eBPF map). Notice that there might be a better choice for the target function, a further investigation is needed.\n\n#### Step 6: Read headers from gRPC response\n\nThe implementation will attach a uprobe to a function that reads the headers from the incoming response. Look for headers with keys according to the W3C Trace Context specification. In gRPC example, we may choose to attach a uprobe to the following function:\n\n```go\nfunc decodeMetadataHeader(k, v string) (string, error)\n```\n\nThis function is located at the `http_util.go` file (again, there may be a better target function, a further investigation is required).\n\n#### Step 7: Update current span map\n\nSimilar to step 4, update the current span map with the headers from the previous step.\n\n#### Step 8: Write headers to HTTP response\n\nSimilar to step 5, the implementation will attach a uprobe to the function that writes the headers to the response.\nA possible candidate may be:\n\n```go\nfunc (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error\n```\n\n## Proof of Concept\n\nThe [following application](https://github.com/edeNFed/ebpf-write-poc) is a test program that demonstrates changing go function arguments via eBPF instrumentation:\n\n```go\nfunc worker(str string) {\n\theaders := make(map[string]string)\n\theaders[\"X-Request-Id\"] = str\n\n\tfmt.Printf(\"The Headers are: %s\\n\", headers)\n}\n\nfunc main() {\n\tfor i := 0; i < 10; i++ {\n\t\tworker(fmt.Sprintf(\"request number: %d\", i))\n\t\ttime.Sleep(2 * time.Second)\n\t}\n}\n```\n\nBy running a [modified version](https://github.com/edeNFed/opentelemetry-go-instrumentation/tree/ebpf-write-poc) of the automatic instrumentation, we can see that the headers are set by the instrumentation successfully:\n\n```\n❯ go run main.go\nThe Headers are: map[X-Request-Id:request number: 0]\nThe Headers are: map[X-Request-Id:request number: 1]\nThe Headers are: map[X-Request-Id:request number: 2]\nThe Headers are: map[X-Request-Id:request number: 3]\nThe Headers are: map[X-Request-Id:request number: 4]\nThe Headers are: map[X-Request-Id:ebpf header value] <--- After instrumentation launched\nThe Headers are: map[X-Request-Id:ebpf header value]\nThe Headers are: map[X-Request-Id:ebpf header value]\n```\n\n## Safety Considerations\n\nModifying function arguments has to be done with care. The automatic instrumentation has all the data required in order to fully understand the stack state and safely modify the arguments:\n\n- Strcutres and data fields offsets (tracked over time by version)\n- Compiled go version\n- CPU architecture\n\nThe process of implementing context propagation will include thorough tests to ensure that the implementation is safe.\n\n## Future Work\n\n- Support more propagation formats like B3 and Jaeger.\n- Configure propagation via environment variables.\n"
  },
  {
    "path": "docs/design/manual-instrumentation.md",
    "content": "# Design Proposal: Integration with Manual Instrumentation\n\n## Motivation\n\nUsers may want to enrich the traces produced by the automatic instrumentation with additional spans created manually via the [OpenTelemetry Go SDK](https://github.com/open-telemetry/opentelemetry-go).\n\n## Overview\n\nIntegration with manual instrumentation happens in two steps:\n\n1. **Modify spans created manually** - attach a uprobe to the function that creates the span, override the trace id and parent span id with the current active span (according to the eBPF map described in the context propagation document).\n2. **Update active span map** - After the span is created, update the eBPF map with the new span as the current span. This step is needed in order to create traces that combines spans created manually, automatically (via other instrumentors) and remotely (via context propagation).\n\nThis implementation depends on changes described in the [Context Propagation design document](context-propagation.md) and can't be implemented before context propagation is implemented.\n\n## Instrumenting OpenTelemetry Go SDK\n\nThe following function (located in `tracer.go` file) may be a good candidate for instrumenting the creation of manual spans:\n\n```go\nfunc (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan {\n```\n\nBy overriding `psc.spanID` and `sc.traceID` to match the current span according to the eBPF map, the function will create a span that is a child of the current active span.\n\n## Future Work\n\n### Use single exporter\n\nApplications instrumented both manually and automatically will export the produced spans via two different exporters. One created manually by the user and another one created in the instrumentation agent. This is not damaging the combined traces, but it is not ideal. In the future, we may want to implement an exporter that communicates with the instrumentation agent (via mechanisem like Unix domain socket) and exports the combined traces over a single connection.\n"
  },
  {
    "path": "docs/getting-started/README.md",
    "content": "# Getting Started with Go OpenTelemetry Automatic Instrumentation\n\nIn this tutorial, we will walk through how to get started with instrumenting the [emojivoto](https://github.com/BuoyantIO/emojivoto) application, a well known microservice example running locally on a Kubernetes cluster.\n\n## Before you begin\n\nThe following tools are required to run this tutorial:\n\n- [Kind](https://kind.sigs.k8s.io/) to run a local Kubernetes cluster with Docker container nodes.\n- [Kubernetes CLI (kubectl)](https://kubernetes.io/docs/tasks/tools/install-kubectl/) to run commands against Kubernetes clusters.\n\n## Creating the Kubernetes cluster\n\nCreate a new local Kubernetes cluster, by running the following command:\n\n```shell\nkind create cluster\n```\n\n## Deployment\n\nThe Kubernetes cluster will run the emojivoto applications and a jaeger UI for visualizing the OpenTelemetry traces:\n\n![Deployed Applications](deployed_apps.jpg)\n\nThe different emojivoto applications are communicating via gRPC. Instrumenting those applications would allow us to view the gRPC requests between the applications.\n\n### Deploying the emojivoto application\n\nRun the following command:\n\n```shell\nkubectl apply -k github.com/keyval-dev/opentelemetry-go-instrumentation/docs/getting-started/emojivoto\n```\n\n### Deploying Jaeger UI\n\nInstall Jaeger UI by running:\n\n```shell\nkubectl apply -f https://raw.githubusercontent.com/keyval-dev/opentelemetry-go-instrumentation/master/docs/getting-started/jaeger.yaml -n emojivoto\n```\n\nThis command installs Jaeger as a new Deployment and an additional Service that we will use later for accessing the Jaeger UI.\n\nIn a real world application, you would probably want to send the tracing data to [OpenTelemetry collector](https://github.com/open-telemetry/opentelemetry-collector) instead of directly to Jaeger.\n\n## Instrumentation\n\nApply the automatic instrumentation to the `emoji`, `voting`, and `web` applications by executing the following command:\n\n```shell\nkubectl apply -f https://raw.githubusercontent.com/keyval-dev/opentelemetry-go-instrumentation/master/docs/getting-started/emojivoto-instrumented.yaml -n emojivoto\n```\n\n## Perform actions on the target Application\n\nNow all that left to do is to perform some actions on the target application that will cause the creation of detailed distributed traces.\n\nPort forward to the frontend service:\n\n```shell\nkubectl port-forward svc/web-svc 8080:80 -n emojivoto\n```\n\nGo to `http://localhost:8080`, and click the **view the leaderboard** button.\n\n## Viewing the traces\n\nFirst, port forward to the Jaeger UI:\n\n```shell\nkubectl port-forward svc/jaeger 16686:16686 -n emojivoto\n```\n\nThen, open the Jaeger UI in your browser by navigating to http://localhost:16686/\n\nAfter selecting the `emojivoto-web` service, you should see the following traces:\n![Traces](jaeger_traces.png)\n\nLet's start with a simple trace, click on one of the `/api/vote` traces, you should see something like the following:\n![vote_trace](vote_trace.png)\n\nA few things worth noticing in this trace:\n- **In process context-propagation**: We can see that the `web` application got an HTTP request (the root span) which caused two sequential gRPC requests to the `emoji` and `voting` services.\n- **Cross process context-propagation**: The automatic instrumentation adds the relevant headers to gRPC / HTTP requests in order to make traces distributed across processes. In Jaeger, different applications are marked in different colors.\n- **Extremely low overhead**: The entire trace took 3.1 milliseconds to complete. This show that using eBPF for instrumentation adds extremely low overhead.\n- **Following OpenTelemetry Specifications**: You can click on any span in the trace to view the different attributes. All the spans produced by the automatic instrumentation follows the OpenTelemetry specification and therefore will work with any OpenTelemetry compatible backend.\n\nNow we will view a more complex trace, search for traces for the `/api/leaderboard` endpoint.\nYou can quickly find them by clicking on the points with the highest duration in Jaeger's main screen.\n![leaderboard_trace](leaderboard_trace.png)\nWe can get a pretty good understanding of how the leaderboard feature works by looking at this trace:\n- First, the web service will perform a gRPC request to the `voting` service to get a list of the available emojis.\n- Second, The web service will loop over the received list of emojis and for every item on the list it will perform a gRPC request to the `emoji` service to get the amount of votes for the current item.\n- As you can see this happens sequentially, which is one of the reason the leaderboard endpoint takes about 150ms to complete.\n\n### Notice that we did not change any application code to get those traces, we are using the exact same containers from the emojivoto project.\n\n## Next Steps\n\nThe easiest way to apply this automatic instrumentation for any application is by using a control plane such as [Odigos](https://github.com/keyval-dev/odigos).\n\nFor more details visit the [Odigos website](https://odigos.io).\n\n## Cleanup\n\nDelete the Kubernetes cluster:\n\n```shell\nkind delete cluster\n```\n"
  },
  {
    "path": "docs/getting-started/emojivoto/emoji.yml",
    "content": "kind: ServiceAccount\napiVersion: v1\nmetadata:\n  name: emoji\n  namespace: emojivoto\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: emoji\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: emoji\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: emoji-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: emoji-svc\n        version: v11\n    spec:\n      serviceAccountName: emoji\n      terminationGracePeriodSeconds: 0\n      containers:\n      - env:\n        - name: GRPC_PORT\n          value: \"8080\"\n        - name: PROM_PORT\n          value: \"8801\"\n        image: docker.l5d.io/buoyantio/emojivoto-emoji-svc:v11\n        name: emoji-svc\n        ports:\n        - containerPort: 8080\n          name: grpc\n        - containerPort: 8801\n          name: prom\n        resources:\n          requests:\n            cpu: 100m\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: emoji-svc\n  namespace: emojivoto\nspec:\n  selector:\n    app: emoji-svc\n  ports:\n  - name: grpc\n    port: 8080\n    targetPort: 8080\n  - name: prom\n    port: 8801\n    targetPort: 8801\n"
  },
  {
    "path": "docs/getting-started/emojivoto/kustomization.yml",
    "content": "resources:\n- ns.yml\n- web.yml\n- emoji.yml\n- voting.yml\n- vote-bot.yml\n"
  },
  {
    "path": "docs/getting-started/emojivoto/ns.yml",
    "content": "apiVersion: v1\nkind: Namespace\nmetadata:\n  name: emojivoto\n"
  },
  {
    "path": "docs/getting-started/emojivoto/vote-bot.yml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: vote-bot\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: vote-bot\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: vote-bot\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: vote-bot\n        version: v11\n    spec:\n      containers:\n      - command:\n        - emojivoto-vote-bot\n        env:\n        - name: WEB_HOST\n          value: web-svc.emojivoto:80\n        image: docker.l5d.io/buoyantio/emojivoto-web:v11\n        name: vote-bot\n        resources:\n          requests:\n            cpu: 10m\n"
  },
  {
    "path": "docs/getting-started/emojivoto/voting.yml",
    "content": "kind: ServiceAccount\napiVersion: v1\nmetadata:\n  name: voting\n  namespace: emojivoto\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: voting\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: voting\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: voting-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: voting-svc\n        version: v11\n    spec:\n      serviceAccountName: voting\n      terminationGracePeriodSeconds: 0\n      containers:\n      - env:\n        - name: GRPC_PORT\n          value: \"8080\"\n        - name: PROM_PORT\n          value: \"8801\"\n        image: docker.l5d.io/buoyantio/emojivoto-voting-svc:v11\n        name: voting-svc\n        ports:\n        - containerPort: 8080\n          name: grpc\n        - containerPort: 8801\n          name: prom\n        resources:\n          requests:\n            cpu: 100m\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: voting-svc\n  namespace: emojivoto\nspec:\n  selector:\n    app: voting-svc\n  ports:\n  - name: grpc\n    port: 8080\n    targetPort: 8080\n  - name: prom\n    port: 8801\n    targetPort: 8801\n"
  },
  {
    "path": "docs/getting-started/emojivoto/web.yml",
    "content": "kind: ServiceAccount\napiVersion: v1\nmetadata:\n  name: web\n  namespace: emojivoto\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: web\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: web\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: web-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: web-svc\n        version: v11\n    spec:\n      serviceAccountName: web\n      terminationGracePeriodSeconds: 0\n      containers:\n      - env:\n        - name: WEB_PORT\n          value: \"8080\"\n        - name: EMOJISVC_HOST\n          value: emoji-svc.emojivoto:8080\n        - name: VOTINGSVC_HOST\n          value: voting-svc.emojivoto:8080\n        - name: INDEX_BUNDLE\n          value: dist/index_bundle.js\n        image: docker.l5d.io/buoyantio/emojivoto-web:v11\n        name: web-svc\n        ports:\n        - containerPort: 8080\n          name: http\n        resources:\n          requests:\n            cpu: 100m\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: web-svc\n  namespace: emojivoto\nspec:\n  type: ClusterIP\n  selector:\n    app: web-svc\n  ports:\n  - name: http\n    port: 80\n    targetPort: 8080\n"
  },
  {
    "path": "docs/getting-started/emojivoto-instrumented.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: emoji\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: emoji\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: emoji-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: emoji-svc\n        version: v11\n    spec:\n      serviceAccountName: emoji\n      shareProcessNamespace: true\n      terminationGracePeriodSeconds: 0\n      initContainers:\n        - name: copy-launcher\n          image: keyval/launcher:v0.1\n          command:\n            - cp\n            - -a\n            - /kv-launcher/.\n            - /odigos-launcher/\n          volumeMounts:\n            - name: launcherdir\n              mountPath: /odigos-launcher\n      containers:\n        - env:\n            - name: GRPC_PORT\n              value: \"8080\"\n            - name: PROM_PORT\n              value: \"8801\"\n          image: docker.l5d.io/buoyantio/emojivoto-emoji-svc:v11\n          name: emoji-svc\n          command:\n            - /odigos-launcher/launch\n            - /usr/local/bin/emojivoto-emoji-svc\n          volumeMounts:\n            - mountPath: /odigos-launcher\n              name: launcherdir\n          ports:\n            - containerPort: 8080\n              name: grpc\n            - containerPort: 8801\n              name: prom\n          resources:\n            requests:\n              cpu: 100m\n        - name: emojivoto-emoji-instrumentation\n          image: keyval/otel-go-agent:v0.6.0\n          env:\n            - name: OTEL_TARGET_EXE\n              value: /usr/local/bin/emojivoto-emoji-svc\n            - name: OTEL_EXPORTER_OTLP_ENDPOINT\n              value: \"jaeger:4317\"\n            - name: OTEL_SERVICE_NAME\n              value: \"emojivoto-emoji\"\n          securityContext:\n            runAsUser: 0\n            capabilities:\n              add:\n                - SYS_PTRACE\n            privileged: true\n          volumeMounts:\n            - mountPath: /sys/kernel/debug\n              name: kernel-debug\n      volumes:\n        - name: launcherdir\n          emptyDir: {}\n        - name: kernel-debug\n          hostPath:\n            path: /sys/kernel/debug\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: voting\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: voting\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: voting-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: voting-svc\n        version: v11\n    spec:\n      serviceAccountName: voting\n      shareProcessNamespace: true\n      terminationGracePeriodSeconds: 0\n      initContainers:\n        - name: copy-launcher\n          image: keyval/launcher:v0.1\n          command:\n            - cp\n            - -a\n            - /kv-launcher/.\n            - /odigos-launcher/\n          volumeMounts:\n            - name: launcherdir\n              mountPath: /odigos-launcher\n      containers:\n        - env:\n            - name: GRPC_PORT\n              value: \"8080\"\n            - name: PROM_PORT\n              value: \"8801\"\n          image: docker.l5d.io/buoyantio/emojivoto-voting-svc:v11\n          name: voting-svc\n          command:\n            - /odigos-launcher/launch\n            - /usr/local/bin/emojivoto-voting-svc\n          volumeMounts:\n            - mountPath: /odigos-launcher\n              name: launcherdir\n          ports:\n            - containerPort: 8080\n              name: grpc\n            - containerPort: 8801\n              name: prom\n          resources:\n            requests:\n              cpu: 100m\n        - name: emojivoto-voting-instrumentation\n          image: keyval/otel-go-agent:v0.6.0\n          env:\n            - name: OTEL_TARGET_EXE\n              value: /usr/local/bin/emojivoto-voting-svc\n            - name: OTEL_EXPORTER_OTLP_ENDPOINT\n              value: \"jaeger:4317\"\n            - name: OTEL_SERVICE_NAME\n              value: \"emojivoto-voting\"\n          securityContext:\n            runAsUser: 0\n            capabilities:\n              add:\n                - SYS_PTRACE\n            privileged: true\n          volumeMounts:\n            - mountPath: /sys/kernel/debug\n              name: kernel-debug\n      volumes:\n        - name: launcherdir\n          emptyDir: {}\n        - name: kernel-debug\n          hostPath:\n            path: /sys/kernel/debug\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: web\n  namespace: emojivoto\n  labels:\n    app.kubernetes.io/name: web\n    app.kubernetes.io/part-of: emojivoto\n    app.kubernetes.io/version: v11\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: web-svc\n      version: v11\n  template:\n    metadata:\n      labels:\n        app: web-svc\n        version: v11\n    spec:\n      serviceAccountName: web\n      shareProcessNamespace: true\n      terminationGracePeriodSeconds: 0\n      initContainers:\n        - name: copy-launcher\n          image: keyval/launcher:v0.1\n          command:\n            - cp\n            - -a\n            - /kv-launcher/.\n            - /odigos-launcher/\n          volumeMounts:\n            - name: launcherdir\n              mountPath: /odigos-launcher\n      containers:\n        - env:\n            - name: WEB_PORT\n              value: \"8080\"\n            - name: EMOJISVC_HOST\n              value: emoji-svc.emojivoto:8080\n            - name: VOTINGSVC_HOST\n              value: voting-svc.emojivoto:8080\n            - name: INDEX_BUNDLE\n              value: dist/index_bundle.js\n          image: docker.l5d.io/buoyantio/emojivoto-web:v11\n          name: web-svc\n          command:\n            - /odigos-launcher/launch\n            - /usr/local/bin/emojivoto-web\n          volumeMounts:\n            - mountPath: /odigos-launcher\n              name: launcherdir\n          ports:\n            - containerPort: 8080\n              name: http\n          resources:\n            requests:\n              cpu: 100m\n        - name: emojivoto-web-instrumentation\n          image: keyval/otel-go-agent:v0.6.0\n          env:\n            - name: OTEL_TARGET_EXE\n              value: /usr/local/bin/emojivoto-web\n            - name: OTEL_EXPORTER_OTLP_ENDPOINT\n              value: \"jaeger:4317\"\n            - name: OTEL_SERVICE_NAME\n              value: \"emojivoto-web\"\n          securityContext:\n            runAsUser: 0\n            capabilities:\n              add:\n                - SYS_PTRACE\n            privileged: true\n          volumeMounts:\n            - mountPath: /sys/kernel/debug\n              name: kernel-debug\n      volumes:\n        - name: launcherdir\n          emptyDir: {}\n        - name: kernel-debug\n          hostPath:\n            path: /sys/kernel/debug"
  },
  {
    "path": "docs/getting-started/jaeger.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app: jaeger\n  name: jaeger\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: jaeger\n  template:\n    metadata:\n      labels:\n        app: jaeger\n    spec:\n      containers:\n      - image: jaegertracing/opentelemetry-all-in-one:latest\n        name: opentelemetry-all-in-one\n---\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: jaeger\n  name: jaeger\nspec:\n  ports:\n  - name: grpc\n    port: 4317\n    targetPort: 4317\n  - name: ui\n    port: 16686\n    targetPort: 16686\n  selector:\n    app: jaeger\n"
  },
  {
    "path": "docs/how-it-works.md",
    "content": "# OpenTelemtry Go Instrumentation - How it works\n\nWe aim to bring the automatic instrumentation experience found in languages like [Java](https://github.com/open-telemetry/opentelemetry-java-instrumentation), [Python](https://github.com/open-telemetry/opentelemetry-python-contrib) and [JavaScript](https://github.com/open-telemetry/opentelemetry-js-contrib) to Go applications.\n\n## Design Goals\n\n- No code changes required - any Go application can be instrumented without modifying the source code.\n- Support wide range of Go applications - instrumentation is supported for Go version 1.12 and above. In addition, a common practice for Go applications is to shrink the binary size by stripping debug symbols via `go build -ldflags \"-s -w\"`. This instrumentation works for stripped binaries as well.\n- Configuration is done via `OTEL_*` environment variables according to [OpenTelemetry Environment Variable Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration)\n- Instrumented libraries follow the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification) and semantic conventions to produce standard OpenTelemetry data.\n\n## Why eBPF\n\nGo is a compiled language. Unlike languages such as Java and Python, Go compiles natively to machine code. This makes it impossible to add additional code at runtime to instrument Go applications.\nFortunately, the Linux kernel provides a mechanism to attach user-defined code to the execution of a process. This is called [eBPF](https://ebpf.io/) and it is widely used in other Cloud Native projects such as Cilium and Falco.\n\n## Main Challenges and How We Overcome Them\n\nUsing eBPF to instrument Go applications is non-trivial. In the following sections we will describe the main challenges and how we solved them.\n\n### Instrumentation Stability\n\neBPF programs access user code and variables by analyzing the stack and the CPU registers. For example, to read the value of the `target` field in the `google.golang.org/grpc.ClientConn` struct (see gRPC instrumentor for an example), the eBPF program needs to know the offset of the field inside the struct. The offset is determined by the field location inside the struct definition.\n\nHard coding this offset information into the eBPF programs creates a very unstable instrumentation. Fields locations inside structs are subject to change and the eBPF program needs to be recompiled every time the struct definition changes.\nLuckily for us, there is a way to analyze the target binary and extract the required offsets, by using DWARF. The DWARF debug information is generated by the compiler and is stored inside the binary.\n\nNotice that one of our design goals is to support stripped Go binaries - meaning binaries that do not contain debug information. In order to support stripped binaries and to create a stable instrumentation, we created a library called [offsets-tracker](https://github.com/keyval-dev/offsets-tracker). This library tracks the offset of different fields across versions.\n\nWe currently track instrumented structs inside the Go standard library and selected open source packages. This solution does not require DWARF information on the target binary and provides stability to instrumentations. Instrumentation authors can get a field location by name instead of hard coding a field offset.\n\nThe offsets-tracker generates the [offset_results.json](https://github.com/keyval-dev/opentelemetry-go-instrumentation/blob/master/pkg/inject/offset_results.json) file. This file contains the offsets of the fields in the instrumented structs.\n\n### Uretprobes\n\nOne of the basic requirments of OpenTelemetry spans is to contain start timestamp and end timestamp. Getting those timestamps is possible by placing an eBPF code at the start and the end of the instrumented function. eBPF supports this requirement via uprobes and uretprobes. Uretprobes are used to invoke eBPF code at the end of the function. Unfortunately, uretprobes and Go [do not play well together](https://github.com/golang/go/issues/22008).\n\nWe overcome this issue by analyzing the target binary and detecting all the return statements in the instrumented functions. We then place a uprobe at the end of each return statement. This uprobe invokes the eBPF code that collects the end timestamp.\n\n### Timestamp tracking\n\neBPF programs can access the current timestamp by calling `bpf_ktime_get_ns()`. The value returned by this function is fetched from the `CLOCK_MONOTONIC` clock and represents the number of nanoseconds since the system boot time.\n\nAccording to OpenTelemetry specification start time and end time should be timestamps and represent exact point in time. Converting from monotonic time to epoch timestamp is automatically handled by this library. Conversion is achieved by discovering the epoch boot time and adding it to the monotonic time collected by the eBPF program.\n\n### Support Go 1.17 and above\n\nSince version 1.17 and above, Go [changed the way it passes arguments to functions](https://go.googlesource.com/go/+/refs/heads/dev.regabi/src/cmd/compile/internal-abi.md#function-call-argument-and-result-passing).\nPrior to version 1.17, Go placed arguments in the stack in the order they were defined in the function signature. Version 1.17 and above uses the machine registers to pass arguments.\n\nWe overcome this by analyzing the target binary and detecting the compiled Go version. If the compiled Go version is 1.17 or above, we read arguments from the machine registers. If the compiled Go version is below 1.17, we read arguments from the stack. This should be transparent to the instrumentation authors and abstracted by a function named `get_argument()`.\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/keyval-dev/opentelemetry-go-instrumentation\n\ngo 1.18\n\nrequire (\n\tgithub.com/cilium/ebpf v0.8.0\n\tgithub.com/go-logr/logr v1.2.3\n\tgithub.com/go-logr/zapr v1.2.2\n\tgithub.com/hashicorp/go-version v1.4.0\n\tgithub.com/prometheus/procfs v0.8.0\n\tgo.opentelemetry.io/otel v1.11.1\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.8.0\n\tgo.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.1\n\tgo.opentelemetry.io/otel/sdk v1.11.1\n\tgo.opentelemetry.io/otel/trace v1.11.1\n\tgo.uber.org/zap v1.20.0\n\tgolang.org/x/arch v0.0.0-20210923205945-b76863e36670\n\tgolang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8\n\tgoogle.golang.org/grpc v1.46.2\n)\n\nrequire (\n\tgithub.com/cenkalti/backoff/v4 v4.1.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/golang/protobuf v1.5.2 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/internal/retry v1.8.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.8.0 // indirect\n\tgo.opentelemetry.io/proto/otlp v0.18.0 // indirect\n\tgo.uber.org/atomic v1.7.0 // indirect\n\tgo.uber.org/multierr v1.6.0 // indirect\n\tgolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect\n\tgolang.org/x/text v0.3.5 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect\n\tgoogle.golang.org/protobuf v1.28.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=\ngithub.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/cilium/ebpf v0.8.0 h1:2V6KSg3FRADVU2BMIRemZ0hV+9OM+aAHhZDjQyjJTAs=\ngithub.com/cilium/ebpf v0.8.0/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=\ngithub.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=\ngithub.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-logr/zapr v1.2.2 h1:5YNlIL6oZLydaV4dOFjL8YpgXF/tPeTbnpatnu3cq6o=\ngithub.com/go-logr/zapr v1.2.2/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=\ngithub.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=\ngithub.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4=\ngithub.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=\ngithub.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=\ngithub.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=\ngithub.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4=\ngo.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE=\ngo.opentelemetry.io/otel/exporters/otlp/internal/retry v1.8.0 h1:ao8CJIShCaIbaMsGxy+jp2YHSudketpDgDRcbirov78=\ngo.opentelemetry.io/otel/exporters/otlp/internal/retry v1.8.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.8.0 h1:LrHL1A3KqIgAgi6mK7Q0aczmzU414AONAGT5xtnp+uo=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.8.0/go.mod h1:w8aZL87GMOvOBa2lU/JlVXE1q4chk/0FX+8ai4513bw=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.8.0 h1:00hCSGLIxdYK/Z7r8GkaX0QIlfvgU3tmnLlQvcnix6U=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.8.0/go.mod h1:twhIvtDQW2sWP1O2cT1N8nkSBgKCRZv2z6COTTBrf8Q=\ngo.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.1 h1:3Yvzs7lgOw8MmbxmLRsQGwYdCubFmUHSooKaEhQunFQ=\ngo.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.11.1/go.mod h1:pyHDt0YlyuENkD2VwHsiRDf+5DfI3EH7pfhUYW6sQUE=\ngo.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs=\ngo.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys=\ngo.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=\ngo.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80=\ngo.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=\ngo.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=\ngo.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=\ngo.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=\ngo.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc=\ngo.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=\ngolang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=\ngolang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "include/alloc.h",
    "content": "#include \"bpf_helpers.h\"\n\n#define MAX_ENTRIES 50\n\n// Injected in init\nvolatile const u32 total_cpus;\nvolatile const u64 start_addr;\nvolatile const u64 end_addr;\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERCPU_HASH);\n\t__type(key, s32);\n\t__type(value, u64);\n\t__uint(max_entries, MAX_ENTRIES);\n\t__uint(pinning, LIBBPF_PIN_BY_NAME);\n} alloc_map SEC(\".maps\");\n\nstatic __always_inline u64 get_area_start() {\n    s64 partition_size = (end_addr - start_addr) / total_cpus;\n    u32 current_cpu = bpf_get_smp_processor_id();\n    s32 start_index = 0;\n    u64* start = (u64*) bpf_map_lookup_elem(&alloc_map, &start_index);\n    if (start == NULL || *start == 0) {\n        u64 current_start_addr = start_addr + (partition_size * current_cpu);\n        bpf_map_update_elem(&alloc_map, &start_index, &current_start_addr, BPF_ANY);\n        return current_start_addr;\n    } else {\n        return *start;\n    }\n}\n\nstatic __always_inline u64 get_area_end(u64 start) {\n    s64 partition_size = (end_addr - start_addr) / total_cpus;\n    s32 end_index = 1;\n    bpf_printk(\"total size: %d, partition size: %d, modulo: %d\", end_addr - start_addr, partition_size, (end_addr - start_addr) % partition_size);\n    u64* end = (u64*)bpf_map_lookup_elem(&alloc_map, &end_index);\n    if (end == NULL || *end == 0) {\n        u64 current_end_addr = start + partition_size;\n        bpf_map_update_elem(&alloc_map, &end_index, &current_end_addr, BPF_ANY);\n        return current_end_addr;\n    } else {\n        return *end;\n    }\n}\n\nstatic __always_inline void* write_target_data(void* data, s32 size) {\n    if (!data || data == NULL) {\n        return NULL;\n    }\n\n    u64 start = get_area_start();\n    u64 end = get_area_end(start);\n    s32 current_cpu = bpf_get_smp_processor_id();\n    if (end - start < size) {\n        bpf_printk(\"reached end of CPU memory block, going to the start again\");\n        s32 start_index = 0;\n        bpf_map_delete_elem(&alloc_map, &start_index);\n        start = get_area_start();\n    }\n\n    void* target = (void*)start;\n    long success = bpf_probe_write_user(target, data, size);\n    if (success == 0) {\n        s32 start_index = 0;\n        u64 updated_start = start + size;\n\n        // align updated_start to 8 bytes\n        if (updated_start % 8 != 0) {\n            updated_start += 8 - (updated_start % 8);\n        }\n\n        bpf_map_update_elem(&alloc_map, &start_index, &updated_start, BPF_ANY);\n        return target;\n    }\n\n    bpf_printk(\"failed to write to userspace, error code: %d, addr: %lx\", success, target);\n    return NULL;\n}"
  },
  {
    "path": "include/arguments.h",
    "content": "#include \"common.h\"\n#include \"bpf_tracing.h\"\n#include \"bpf_helpers.h\"\n#include <stdbool.h>\n\n// Injected in init\nvolatile const bool is_registers_abi;\n\nvoid* get_argument_by_reg(struct pt_regs *ctx, int index) {\n    switch (index) {\n        case 1:\n            return (void*)GO_PARAM1(ctx);\n        case 2:\n            return (void*)GO_PARAM2(ctx);\n        case 3:\n            return (void*)GO_PARAM3(ctx);\n        case 4:\n            return (void*)GO_PARAM4(ctx);\n        case 5:\n            return (void*)GO_PARAM5(ctx);\n        case 6:\n            return (void*)GO_PARAM6(ctx);\n        case 7:\n            return (void*)GO_PARAM7(ctx);\n        case 8:\n            return (void*)GO_PARAM8(ctx);\n        case 9:\n            return (void*)GO_PARAM9(ctx);\n        default:\n            return NULL;\n    }\n}\n\nvoid* get_argument_by_stack(struct pt_regs *ctx, int index) {\n    void* ptr = 0;\n    bpf_probe_read(&ptr, sizeof(ptr), (void *)(PT_REGS_SP(ctx)+(index*8)));\n    return ptr;\n}\n\nvoid* get_argument(struct pt_regs *ctx, int index) {\n    if (is_registers_abi) {\n        return get_argument_by_reg(ctx, index);\n    }\n\n    return get_argument_by_stack(ctx, index);\n}"
  },
  {
    "path": "include/common.h",
    "content": "// This is a compact version of `vmlinux.h`\n\n#define MAX_OS_THREADS 20\n\n#ifndef __VMLINUX_H__\n#define __VMLINUX_H__\n\ntypedef unsigned char __u8;\ntypedef short int __s16;\ntypedef short unsigned int __u16;\ntypedef int __s32;\ntypedef unsigned int __u32;\ntypedef long long int __s64;\ntypedef long long unsigned int __u64;\ntypedef __u8 u8;\ntypedef __s16 s16;\ntypedef __u16 u16;\ntypedef __s32 s32;\ntypedef __u32 u32;\ntypedef __s64 s64;\ntypedef __u64 u64;\ntypedef __u16 __le16;\ntypedef __u16 __be16;\ntypedef __u32 __be32;\ntypedef __u64 __be64;\ntypedef __u32 __wsum;\n\nenum bpf_map_type {\n\tBPF_MAP_TYPE_UNSPEC = 0,\n\tBPF_MAP_TYPE_HASH = 1,\n\tBPF_MAP_TYPE_ARRAY = 2,\n\tBPF_MAP_TYPE_PROG_ARRAY = 3,\n\tBPF_MAP_TYPE_PERF_EVENT_ARRAY = 4,\n\tBPF_MAP_TYPE_PERCPU_HASH = 5,\n\tBPF_MAP_TYPE_PERCPU_ARRAY = 6,\n\tBPF_MAP_TYPE_STACK_TRACE = 7,\n\tBPF_MAP_TYPE_CGROUP_ARRAY = 8,\n\tBPF_MAP_TYPE_LRU_HASH = 9,\n\tBPF_MAP_TYPE_LRU_PERCPU_HASH = 10,\n\tBPF_MAP_TYPE_LPM_TRIE = 11,\n\tBPF_MAP_TYPE_ARRAY_OF_MAPS = 12,\n\tBPF_MAP_TYPE_HASH_OF_MAPS = 13,\n\tBPF_MAP_TYPE_DEVMAP = 14,\n\tBPF_MAP_TYPE_SOCKMAP = 15,\n\tBPF_MAP_TYPE_CPUMAP = 16,\n\tBPF_MAP_TYPE_XSKMAP = 17,\n\tBPF_MAP_TYPE_SOCKHASH = 18,\n\tBPF_MAP_TYPE_CGROUP_STORAGE = 19,\n\tBPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20,\n\tBPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21,\n\tBPF_MAP_TYPE_QUEUE = 22,\n\tBPF_MAP_TYPE_STACK = 23,\n\tBPF_MAP_TYPE_SK_STORAGE = 24,\n\tBPF_MAP_TYPE_DEVMAP_HASH = 25,\n\tBPF_MAP_TYPE_STRUCT_OPS = 26,\n\tBPF_MAP_TYPE_RINGBUF = 27,\n\tBPF_MAP_TYPE_INODE_STORAGE = 28,\n};\n\nenum {\n\tBPF_ANY = 0,\n\tBPF_NOEXIST = 1,\n\tBPF_EXIST = 2,\n\tBPF_F_LOCK = 4,\n};\n\n/* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and\n * BPF_FUNC_perf_event_read_value flags.\n */\n#define BPF_F_INDEX_MASK 0xffffffffULL\n#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK\n\n#if defined(__TARGET_ARCH_x86)\nstruct pt_regs {\n\tlong unsigned int r15;\n\tlong unsigned int r14;\n\tlong unsigned int r13;\n\tlong unsigned int r12;\n\tlong unsigned int bp;\n\tlong unsigned int bx;\n\tlong unsigned int r11;\n\tlong unsigned int r10;\n\tlong unsigned int r9;\n\tlong unsigned int r8;\n\tlong unsigned int ax;\n\tlong unsigned int cx;\n\tlong unsigned int dx;\n\tlong unsigned int si;\n\tlong unsigned int di;\n\tlong unsigned int orig_ax;\n\tlong unsigned int ip;\n\tlong unsigned int cs;\n\tlong unsigned int flags;\n\tlong unsigned int sp;\n\tlong unsigned int ss;\n};\n#elif defined(__TARGET_ARCH_arm64)\nstruct user_pt_regs {\n\t__u64 regs[31];\n\t__u64 sp;\n\t__u64 pc;\n\t__u64 pstate;\n};\n\nstruct pt_regs {\n\tunion {\n\t\tstruct user_pt_regs user_regs;\n\t\tstruct {\n\t\t\tu64 regs[31];\n\t\t\tu64 sp;\n\t\t\tu64 pc;\n\t\t\tu64 pstate;\n\t\t};\n\t};\n\tu64 orig_x0;\n\ts32 syscallno;\n\tu32 unused2;\n\tu64 orig_addr_limit;\n\tu64 pmr_save;\n\tu64 stackframe[2];\n\tu64 lockdep_hardirqs;\n\tu64 exit_rcu;\n};\n#endif\n\n#endif /* __VMLINUX_H__ */"
  },
  {
    "path": "include/go_context.h",
    "content": "#include \"bpf_helpers.h\"\n\n#define MAX_DISTANCE 10\n\nstatic __always_inline void* find_context_in_map(void *ctx, void *context_map) {\n    void *data = ctx;\n    for (int i = 0; i < MAX_DISTANCE; i++) {\n        void* found_in_map = bpf_map_lookup_elem(context_map, &data);\n        if (found_in_map != NULL) {\n            return data;\n        }\n\n        // We assume context.Context implementation containens Parent context.Context member\n        // Since the parent is also an interface, we need to read the data part of it\n        bpf_probe_read(&data, sizeof(data), data+8);\n    }\n\n    bpf_printk(\"context %lx not found in context map\", ctx);\n    return NULL;\n}"
  },
  {
    "path": "include/go_types.h",
    "content": "#include \"alloc.h\"\n#include \"bpf_helpers.h\"\n\n#define MAX_REALLOCATION 400\n#define MAX_DATA_SIZE 400\n\nstruct go_string {\n    char* str;\n    s32 len;\n};\n\nstruct go_slice {\n    void* array;\n    s32 len;\n    s32 cap;\n};\n\nstruct go_slice_user_ptr {\n    void* array;\n    void* len;\n    void* cap;\n};\n\nstruct go_iface {\n    void* tab;\n    void* data;\n};\n\nstatic __always_inline struct go_string write_user_go_string(char* str, u32 len) {\n    // Copy chars to userspace\n    char *addr = write_target_data((void*)str, len);\n\n    // Build string struct in kernel space\n    struct go_string new_string = {};\n    new_string.str = addr;\n    new_string.len = len;\n\n    // Copy new string struct to userspace\n    void* res = write_target_data((void*)&new_string, sizeof(new_string));\n    if (res == NULL) {\n        new_string.len = 0;\n    }\n\n    return new_string;\n}\n\nstatic __always_inline void append_item_to_slice(struct go_slice *slice, void* new_item, s32 item_size, struct go_slice_user_ptr *slice_user_ptr, void* buff) {\n    if (slice->len < slice->cap) {\n        // Room available on current array\n        bpf_probe_write_user(slice->array+(item_size*slice->len), new_item, item_size);\n    } else {\n        // No room on current array - copy to new one of size item_size * (len + 1)\n        if (slice->len > MAX_DATA_SIZE || slice->len < 1) {\n            return;\n        }\n\n        s32 alloc_size = item_size * slice->len;\n        s32 bounded_alloc_size = alloc_size > MAX_REALLOCATION ? MAX_REALLOCATION : (alloc_size < 1 ? 1 : alloc_size);\n\n        // Get buffer\n        s32 index = 0;\n        void* map_buff = bpf_map_lookup_elem(buff, &index);\n        if (!map_buff) {\n            return;\n        }\n\n        // Append to buffer\n        bpf_probe_read_user(map_buff, bounded_alloc_size, slice->array);\n        bpf_probe_read(map_buff+bounded_alloc_size, item_size, new_item);\n\n        // Copy buffer to userspace\n        u32 new_array_size = bounded_alloc_size+item_size;\n        if (new_array_size > MAX_DATA_SIZE || new_array_size < 1) {\n            return;\n        }\n\n        void* new_array = write_target_data(map_buff, new_array_size);\n\n        // Update array\n        slice->array = new_array;\n        long success = bpf_probe_write_user(slice_user_ptr->array, &slice->array, sizeof(slice->array));\n\n        // Update cap\n        slice->cap++;\n        success = bpf_probe_write_user(slice_user_ptr->cap, &slice->cap, sizeof(slice->cap));\n    }\n\n    // Update len\n    slice->len++;\n    long success = bpf_probe_write_user(slice_user_ptr->len, &slice->len, sizeof(slice->len));\n}"
  },
  {
    "path": "include/libbpf/bpf.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n\n/*\n * common eBPF ELF operations.\n *\n * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>\n * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>\n * Copyright (C) 2015 Huawei Inc.\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation;\n * version 2.1 of the License (not later!)\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this program; if not,  see <http://www.gnu.org/licenses>\n */\n#ifndef __LIBBPF_BPF_H\n#define __LIBBPF_BPF_H\n\n#include <linux/bpf.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"libbpf_common.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct bpf_create_map_attr {\n\tconst char *name;\n\tenum bpf_map_type map_type;\n\t__u32 map_flags;\n\t__u32 key_size;\n\t__u32 value_size;\n\t__u32 max_entries;\n\t__u32 numa_node;\n\t__u32 btf_fd;\n\t__u32 btf_key_type_id;\n\t__u32 btf_value_type_id;\n\t__u32 map_ifindex;\n\tunion {\n\t\t__u32 inner_map_fd;\n\t\t__u32 btf_vmlinux_value_type_id;\n\t};\n};\n\nLIBBPF_API int\nbpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);\nLIBBPF_API int bpf_create_map_node(enum bpf_map_type map_type, const char *name,\n\t\t\t\t   int key_size, int value_size,\n\t\t\t\t   int max_entries, __u32 map_flags, int node);\nLIBBPF_API int bpf_create_map_name(enum bpf_map_type map_type, const char *name,\n\t\t\t\t   int key_size, int value_size,\n\t\t\t\t   int max_entries, __u32 map_flags);\nLIBBPF_API int bpf_create_map(enum bpf_map_type map_type, int key_size,\n\t\t\t      int value_size, int max_entries, __u32 map_flags);\nLIBBPF_API int bpf_create_map_in_map_node(enum bpf_map_type map_type,\n\t\t\t\t\t  const char *name, int key_size,\n\t\t\t\t\t  int inner_map_fd, int max_entries,\n\t\t\t\t\t  __u32 map_flags, int node);\nLIBBPF_API int bpf_create_map_in_map(enum bpf_map_type map_type,\n\t\t\t\t     const char *name, int key_size,\n\t\t\t\t     int inner_map_fd, int max_entries,\n\t\t\t\t     __u32 map_flags);\n\nstruct bpf_load_program_attr {\n\tenum bpf_prog_type prog_type;\n\tenum bpf_attach_type expected_attach_type;\n\tconst char *name;\n\tconst struct bpf_insn *insns;\n\tsize_t insns_cnt;\n\tconst char *license;\n\tunion {\n\t\t__u32 kern_version;\n\t\t__u32 attach_prog_fd;\n\t};\n\tunion {\n\t\t__u32 prog_ifindex;\n\t\t__u32 attach_btf_id;\n\t};\n\t__u32 prog_btf_fd;\n\t__u32 func_info_rec_size;\n\tconst void *func_info;\n\t__u32 func_info_cnt;\n\t__u32 line_info_rec_size;\n\tconst void *line_info;\n\t__u32 line_info_cnt;\n\t__u32 log_level;\n\t__u32 prog_flags;\n};\n\n/* Flags to direct loading requirements */\n#define MAPS_RELAX_COMPAT\t0x01\n\n/* Recommend log buffer size */\n#define BPF_LOG_BUF_SIZE (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */\nLIBBPF_API int\nbpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,\n\t\t       char *log_buf, size_t log_buf_sz);\nLIBBPF_API int bpf_load_program(enum bpf_prog_type type,\n\t\t\t\tconst struct bpf_insn *insns, size_t insns_cnt,\n\t\t\t\tconst char *license, __u32 kern_version,\n\t\t\t\tchar *log_buf, size_t log_buf_sz);\nLIBBPF_API int bpf_verify_program(enum bpf_prog_type type,\n\t\t\t\t  const struct bpf_insn *insns,\n\t\t\t\t  size_t insns_cnt, __u32 prog_flags,\n\t\t\t\t  const char *license, __u32 kern_version,\n\t\t\t\t  char *log_buf, size_t log_buf_sz,\n\t\t\t\t  int log_level);\n\nLIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value,\n\t\t\t\t   __u64 flags);\n\nLIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value);\nLIBBPF_API int bpf_map_lookup_elem_flags(int fd, const void *key, void *value,\n\t\t\t\t\t __u64 flags);\nLIBBPF_API int bpf_map_lookup_and_delete_elem(int fd, const void *key,\n\t\t\t\t\t      void *value);\nLIBBPF_API int bpf_map_lookup_and_delete_elem_flags(int fd, const void *key,\n\t\t\t\t\t\t    void *value, __u64 flags);\nLIBBPF_API int bpf_map_delete_elem(int fd, const void *key);\nLIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key);\nLIBBPF_API int bpf_map_freeze(int fd);\n\nstruct bpf_map_batch_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\t__u64 elem_flags;\n\t__u64 flags;\n};\n#define bpf_map_batch_opts__last_field flags\n\nLIBBPF_API int bpf_map_delete_batch(int fd, void *keys,\n\t\t\t\t    __u32 *count,\n\t\t\t\t    const struct bpf_map_batch_opts *opts);\nLIBBPF_API int bpf_map_lookup_batch(int fd, void *in_batch, void *out_batch,\n\t\t\t\t    void *keys, void *values, __u32 *count,\n\t\t\t\t    const struct bpf_map_batch_opts *opts);\nLIBBPF_API int bpf_map_lookup_and_delete_batch(int fd, void *in_batch,\n\t\t\t\t\tvoid *out_batch, void *keys,\n\t\t\t\t\tvoid *values, __u32 *count,\n\t\t\t\t\tconst struct bpf_map_batch_opts *opts);\nLIBBPF_API int bpf_map_update_batch(int fd, void *keys, void *values,\n\t\t\t\t    __u32 *count,\n\t\t\t\t    const struct bpf_map_batch_opts *opts);\n\nLIBBPF_API int bpf_obj_pin(int fd, const char *pathname);\nLIBBPF_API int bpf_obj_get(const char *pathname);\n\nstruct bpf_prog_attach_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\tunsigned int flags;\n\tint replace_prog_fd;\n};\n#define bpf_prog_attach_opts__last_field replace_prog_fd\n\nLIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,\n\t\t\t       enum bpf_attach_type type, unsigned int flags);\nLIBBPF_API int bpf_prog_attach_xattr(int prog_fd, int attachable_fd,\n\t\t\t\t     enum bpf_attach_type type,\n\t\t\t\t     const struct bpf_prog_attach_opts *opts);\nLIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);\nLIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,\n\t\t\t\tenum bpf_attach_type type);\n\nunion bpf_iter_link_info; /* defined in up-to-date linux/bpf.h */\nstruct bpf_link_create_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\t__u32 flags;\n\tunion bpf_iter_link_info *iter_info;\n\t__u32 iter_info_len;\n\t__u32 target_btf_id;\n\tunion {\n\t\tstruct {\n\t\t\t__u64 bpf_cookie;\n\t\t} perf_event;\n\t};\n\tsize_t :0;\n};\n#define bpf_link_create_opts__last_field perf_event\n\nLIBBPF_API int bpf_link_create(int prog_fd, int target_fd,\n\t\t\t       enum bpf_attach_type attach_type,\n\t\t\t       const struct bpf_link_create_opts *opts);\n\nLIBBPF_API int bpf_link_detach(int link_fd);\n\nstruct bpf_link_update_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\t__u32 flags;\t   /* extra flags */\n\t__u32 old_prog_fd; /* expected old program FD */\n};\n#define bpf_link_update_opts__last_field old_prog_fd\n\nLIBBPF_API int bpf_link_update(int link_fd, int new_prog_fd,\n\t\t\t       const struct bpf_link_update_opts *opts);\n\nLIBBPF_API int bpf_iter_create(int link_fd);\n\nstruct bpf_prog_test_run_attr {\n\tint prog_fd;\n\tint repeat;\n\tconst void *data_in;\n\t__u32 data_size_in;\n\tvoid *data_out;      /* optional */\n\t__u32 data_size_out; /* in: max length of data_out\n\t\t\t      * out: length of data_out */\n\t__u32 retval;        /* out: return code of the BPF program */\n\t__u32 duration;      /* out: average per repetition in ns */\n\tconst void *ctx_in; /* optional */\n\t__u32 ctx_size_in;\n\tvoid *ctx_out;      /* optional */\n\t__u32 ctx_size_out; /* in: max length of ctx_out\n\t\t\t     * out: length of cxt_out */\n};\n\nLIBBPF_API int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr);\n\n/*\n * bpf_prog_test_run does not check that data_out is large enough. Consider\n * using bpf_prog_test_run_xattr instead.\n */\nLIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,\n\t\t\t\t __u32 size, void *data_out, __u32 *size_out,\n\t\t\t\t __u32 *retval, __u32 *duration);\nLIBBPF_API int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id);\nLIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);\nLIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);\nLIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);\nLIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);\nLIBBPF_API int bpf_map_get_fd_by_id(__u32 id);\nLIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);\nLIBBPF_API int bpf_link_get_fd_by_id(__u32 id);\nLIBBPF_API int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len);\nLIBBPF_API int bpf_prog_query(int target_fd, enum bpf_attach_type type,\n\t\t\t      __u32 query_flags, __u32 *attach_flags,\n\t\t\t      __u32 *prog_ids, __u32 *prog_cnt);\nLIBBPF_API int bpf_raw_tracepoint_open(const char *name, int prog_fd);\nLIBBPF_API int bpf_load_btf(const void *btf, __u32 btf_size, char *log_buf,\n\t\t\t    __u32 log_buf_size, bool do_log);\nLIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,\n\t\t\t\t __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,\n\t\t\t\t __u64 *probe_offset, __u64 *probe_addr);\n\nenum bpf_stats_type; /* defined in up-to-date linux/bpf.h */\nLIBBPF_API int bpf_enable_stats(enum bpf_stats_type type);\n\nstruct bpf_prog_bind_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\t__u32 flags;\n};\n#define bpf_prog_bind_opts__last_field flags\n\nLIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd,\n\t\t\t\t const struct bpf_prog_bind_opts *opts);\n\nstruct bpf_test_run_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\tconst void *data_in; /* optional */\n\tvoid *data_out;      /* optional */\n\t__u32 data_size_in;\n\t__u32 data_size_out; /* in: max length of data_out\n\t\t\t      * out: length of data_out\n\t\t\t      */\n\tconst void *ctx_in; /* optional */\n\tvoid *ctx_out;      /* optional */\n\t__u32 ctx_size_in;\n\t__u32 ctx_size_out; /* in: max length of ctx_out\n\t\t\t     * out: length of cxt_out\n\t\t\t     */\n\t__u32 retval;        /* out: return code of the BPF program */\n\tint repeat;\n\t__u32 duration;      /* out: average per repetition in ns */\n\t__u32 flags;\n\t__u32 cpu;\n};\n#define bpf_test_run_opts__last_field cpu\n\nLIBBPF_API int bpf_prog_test_run_opts(int prog_fd,\n\t\t\t\t      struct bpf_test_run_opts *opts);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* __LIBBPF_BPF_H */\n"
  },
  {
    "path": "include/libbpf/bpf_core_read.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_CORE_READ_H__\n#define __BPF_CORE_READ_H__\n\n/*\n * enum bpf_field_info_kind is passed as a second argument into\n * __builtin_preserve_field_info() built-in to get a specific aspect of\n * a field, captured as a first argument. __builtin_preserve_field_info(field,\n * info_kind) returns __u32 integer and produces BTF field relocation, which\n * is understood and processed by libbpf during BPF object loading. See\n * selftests/bpf for examples.\n */\nenum bpf_field_info_kind {\n\tBPF_FIELD_BYTE_OFFSET = 0,\t/* field byte offset */\n\tBPF_FIELD_BYTE_SIZE = 1,\n\tBPF_FIELD_EXISTS = 2,\t\t/* field existence in target kernel */\n\tBPF_FIELD_SIGNED = 3,\n\tBPF_FIELD_LSHIFT_U64 = 4,\n\tBPF_FIELD_RSHIFT_U64 = 5,\n};\n\n/* second argument to __builtin_btf_type_id() built-in */\nenum bpf_type_id_kind {\n\tBPF_TYPE_ID_LOCAL = 0,\t\t/* BTF type ID in local program */\n\tBPF_TYPE_ID_TARGET = 1,\t\t/* BTF type ID in target kernel */\n};\n\n/* second argument to __builtin_preserve_type_info() built-in */\nenum bpf_type_info_kind {\n\tBPF_TYPE_EXISTS = 0,\t\t/* type existence in target kernel */\n\tBPF_TYPE_SIZE = 1,\t\t/* type size in target kernel */\n};\n\n/* second argument to __builtin_preserve_enum_value() built-in */\nenum bpf_enum_value_kind {\n\tBPF_ENUMVAL_EXISTS = 0,\t\t/* enum value existence in kernel */\n\tBPF_ENUMVAL_VALUE = 1,\t\t/* enum value value relocation */\n};\n\n#define __CORE_RELO(src, field, info)\t\t\t\t\t      \\\n\t__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)\n\n#if __BYTE_ORDER == __LITTLE_ENDIAN\n#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)\t\t\t      \\\n\tbpf_probe_read_kernel(\t\t\t\t\t\t      \\\n\t\t\t(void *)dst,\t\t\t\t      \\\n\t\t\t__CORE_RELO(src, fld, BYTE_SIZE),\t\t      \\\n\t\t\t(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))\n#else\n/* semantics of LSHIFT_64 assumes loading values into low-ordered bytes, so\n * for big-endian we need to adjust destination pointer accordingly, based on\n * field byte size\n */\n#define __CORE_BITFIELD_PROBE_READ(dst, src, fld)\t\t\t      \\\n\tbpf_probe_read_kernel(\t\t\t\t\t\t      \\\n\t\t\t(void *)dst + (8 - __CORE_RELO(src, fld, BYTE_SIZE)), \\\n\t\t\t__CORE_RELO(src, fld, BYTE_SIZE),\t\t      \\\n\t\t\t(const void *)src + __CORE_RELO(src, fld, BYTE_OFFSET))\n#endif\n\n/*\n * Extract bitfield, identified by s->field, and return its value as u64.\n * All this is done in relocatable manner, so bitfield changes such as\n * signedness, bit size, offset changes, this will be handled automatically.\n * This version of macro is using bpf_probe_read_kernel() to read underlying\n * integer storage. Macro functions as an expression and its return type is\n * bpf_probe_read_kernel()'s return value: 0, on success, <0 on error.\n */\n#define BPF_CORE_READ_BITFIELD_PROBED(s, field) ({\t\t\t      \\\n\tunsigned long long val = 0;\t\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\t__CORE_BITFIELD_PROBE_READ(&val, s, field);\t\t\t      \\\n\tval <<= __CORE_RELO(s, field, LSHIFT_U64);\t\t\t      \\\n\tif (__CORE_RELO(s, field, SIGNED))\t\t\t\t      \\\n\t\tval = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \\\n\telse\t\t\t\t\t\t\t\t      \\\n\t\tval = val >> __CORE_RELO(s, field, RSHIFT_U64);\t\t      \\\n\tval;\t\t\t\t\t\t\t\t      \\\n})\n\n/*\n * Extract bitfield, identified by s->field, and return its value as u64.\n * This version of macro is using direct memory reads and should be used from\n * BPF program types that support such functionality (e.g., typed raw\n * tracepoints).\n */\n#define BPF_CORE_READ_BITFIELD(s, field) ({\t\t\t\t      \\\n\tconst void *p = (const void *)s + __CORE_RELO(s, field, BYTE_OFFSET); \\\n\tunsigned long long val;\t\t\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\t/* This is a so-called barrier_var() operation that makes specified   \\\n\t * variable \"a black box\" for optimizing compiler.\t\t      \\\n\t * It forces compiler to perform BYTE_OFFSET relocation on p and use  \\\n\t * its calculated value in the switch below, instead of applying      \\\n\t * the same relocation 4 times for each individual memory load.       \\\n\t */\t\t\t\t\t\t\t\t      \\\n\tasm volatile(\"\" : \"=r\"(p) : \"0\"(p));\t\t\t\t      \\\n\t\t\t\t\t\t\t\t\t      \\\n\tswitch (__CORE_RELO(s, field, BYTE_SIZE)) {\t\t\t      \\\n\tcase 1: val = *(const unsigned char *)p; break;\t\t\t      \\\n\tcase 2: val = *(const unsigned short *)p; break;\t\t      \\\n\tcase 4: val = *(const unsigned int *)p; break;\t\t\t      \\\n\tcase 8: val = *(const unsigned long long *)p; break;\t\t      \\\n\t}\t\t\t\t\t\t\t\t      \\\n\tval <<= __CORE_RELO(s, field, LSHIFT_U64);\t\t\t      \\\n\tif (__CORE_RELO(s, field, SIGNED))\t\t\t\t      \\\n\t\tval = ((long long)val) >> __CORE_RELO(s, field, RSHIFT_U64);  \\\n\telse\t\t\t\t\t\t\t\t      \\\n\t\tval = val >> __CORE_RELO(s, field, RSHIFT_U64);\t\t      \\\n\tval;\t\t\t\t\t\t\t\t      \\\n})\n\n/*\n * Convenience macro to check that field actually exists in target kernel's.\n * Returns:\n *    1, if matching field is present in target kernel;\n *    0, if no matching field found.\n */\n#define bpf_core_field_exists(field)\t\t\t\t\t    \\\n\t__builtin_preserve_field_info(field, BPF_FIELD_EXISTS)\n\n/*\n * Convenience macro to get the byte size of a field. Works for integers,\n * struct/unions, pointers, arrays, and enums.\n */\n#define bpf_core_field_size(field)\t\t\t\t\t    \\\n\t__builtin_preserve_field_info(field, BPF_FIELD_BYTE_SIZE)\n\n/*\n * Convenience macro to get BTF type ID of a specified type, using a local BTF\n * information. Return 32-bit unsigned integer with type ID from program's own\n * BTF. Always succeeds.\n */\n#define bpf_core_type_id_local(type)\t\t\t\t\t    \\\n\t__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)\n\n/*\n * Convenience macro to get BTF type ID of a target kernel's type that matches\n * specified local type.\n * Returns:\n *    - valid 32-bit unsigned type ID in kernel BTF;\n *    - 0, if no matching type was found in a target kernel BTF.\n */\n#define bpf_core_type_id_kernel(type)\t\t\t\t\t    \\\n\t__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)\n\n/*\n * Convenience macro to check that provided named type\n * (struct/union/enum/typedef) exists in a target kernel.\n * Returns:\n *    1, if such type is present in target kernel's BTF;\n *    0, if no matching type is found.\n */\n#define bpf_core_type_exists(type)\t\t\t\t\t    \\\n\t__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)\n\n/*\n * Convenience macro to get the byte size of a provided named type\n * (struct/union/enum/typedef) in a target kernel.\n * Returns:\n *    >= 0 size (in bytes), if type is present in target kernel's BTF;\n *    0, if no matching type is found.\n */\n#define bpf_core_type_size(type)\t\t\t\t\t    \\\n\t__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)\n\n/*\n * Convenience macro to check that provided enumerator value is defined in\n * a target kernel.\n * Returns:\n *    1, if specified enum type and its enumerator value are present in target\n *    kernel's BTF;\n *    0, if no matching enum and/or enum value within that enum is found.\n */\n#define bpf_core_enum_value_exists(enum_type, enum_value)\t\t    \\\n\t__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)\n\n/*\n * Convenience macro to get the integer value of an enumerator value in\n * a target kernel.\n * Returns:\n *    64-bit value, if specified enum type and its enumerator value are\n *    present in target kernel's BTF;\n *    0, if no matching enum and/or enum value within that enum is found.\n */\n#define bpf_core_enum_value(enum_type, enum_value)\t\t\t    \\\n\t__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)\n\n/*\n * bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures\n * offset relocation for source address using __builtin_preserve_access_index()\n * built-in, provided by Clang.\n *\n * __builtin_preserve_access_index() takes as an argument an expression of\n * taking an address of a field within struct/union. It makes compiler emit\n * a relocation, which records BTF type ID describing root struct/union and an\n * accessor string which describes exact embedded field that was used to take\n * an address. See detailed description of this relocation format and\n * semantics in comments to struct bpf_field_reloc in libbpf_internal.h.\n *\n * This relocation allows libbpf to adjust BPF instruction to use correct\n * actual field offset, based on target kernel BTF type that matches original\n * (local) BTF, used to record relocation.\n */\n#define bpf_core_read(dst, sz, src)\t\t\t\t\t    \\\n\tbpf_probe_read_kernel(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */\n#define bpf_core_read_user(dst, sz, src)\t\t\t\t    \\\n\tbpf_probe_read_user(dst, sz, (const void *)__builtin_preserve_access_index(src))\n/*\n * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str()\n * additionally emitting BPF CO-RE field relocation for specified source\n * argument.\n */\n#define bpf_core_read_str(dst, sz, src)\t\t\t\t\t    \\\n\tbpf_probe_read_kernel_str(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n/* NOTE: see comments for BPF_CORE_READ_USER() about the proper types use. */\n#define bpf_core_read_user_str(dst, sz, src)\t\t\t\t    \\\n\tbpf_probe_read_user_str(dst, sz, (const void *)__builtin_preserve_access_index(src))\n\n#define ___concat(a, b) a ## b\n#define ___apply(fn, n) ___concat(fn, n)\n#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N\n\n/*\n * return number of provided arguments; used for switch-based variadic macro\n * definitions (see ___last, ___arrow, etc below)\n */\n#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n/*\n * return 0 if no arguments are passed, N - otherwise; used for\n * recursively-defined macros to specify termination (0) case, and generic\n * (N) case (e.g., ___read_ptrs, ___core_read)\n */\n#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0)\n\n#define ___last1(x) x\n#define ___last2(a, x) x\n#define ___last3(a, b, x) x\n#define ___last4(a, b, c, x) x\n#define ___last5(a, b, c, d, x) x\n#define ___last6(a, b, c, d, e, x) x\n#define ___last7(a, b, c, d, e, f, x) x\n#define ___last8(a, b, c, d, e, f, g, x) x\n#define ___last9(a, b, c, d, e, f, g, h, x) x\n#define ___last10(a, b, c, d, e, f, g, h, i, x) x\n#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___nolast2(a, _) a\n#define ___nolast3(a, b, _) a, b\n#define ___nolast4(a, b, c, _) a, b, c\n#define ___nolast5(a, b, c, d, _) a, b, c, d\n#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e\n#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f\n#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g\n#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h\n#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i\n#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___arrow1(a) a\n#define ___arrow2(a, b) a->b\n#define ___arrow3(a, b, c) a->b->c\n#define ___arrow4(a, b, c, d) a->b->c->d\n#define ___arrow5(a, b, c, d, e) a->b->c->d->e\n#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f\n#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g\n#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h\n#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i\n#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j\n#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__)\n\n#define ___type(...) typeof(___arrow(__VA_ARGS__))\n\n#define ___read(read_fn, dst, src_type, src, accessor)\t\t\t    \\\n\tread_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor)\n\n/* \"recursively\" read a sequence of inner pointers using local __t var */\n#define ___rd_first(fn, src, a) ___read(fn, &__t, ___type(src), src, a);\n#define ___rd_last(fn, ...)\t\t\t\t\t\t    \\\n\t___read(fn, &__t, ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__));\n#define ___rd_p1(fn, ...) const void *__t; ___rd_first(fn, __VA_ARGS__)\n#define ___rd_p2(fn, ...) ___rd_p1(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p3(fn, ...) ___rd_p2(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p4(fn, ...) ___rd_p3(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p5(fn, ...) ___rd_p4(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p6(fn, ...) ___rd_p5(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p7(fn, ...) ___rd_p6(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p8(fn, ...) ___rd_p7(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___rd_p9(fn, ...) ___rd_p8(fn, ___nolast(__VA_ARGS__)) ___rd_last(fn, __VA_ARGS__)\n#define ___read_ptrs(fn, src, ...)\t\t\t\t\t    \\\n\t___apply(___rd_p, ___narg(__VA_ARGS__))(fn, src, __VA_ARGS__)\n\n#define ___core_read0(fn, fn_ptr, dst, src, a)\t\t\t\t    \\\n\t___read(fn, dst, ___type(src), src, a);\n#define ___core_readN(fn, fn_ptr, dst, src, ...)\t\t\t    \\\n\t___read_ptrs(fn_ptr, src, ___nolast(__VA_ARGS__))\t\t    \\\n\t___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t,\t    \\\n\t\t___last(__VA_ARGS__));\n#define ___core_read(fn, fn_ptr, dst, src, a, ...)\t\t\t    \\\n\t___apply(___core_read, ___empty(__VA_ARGS__))(fn, fn_ptr, dst,\t    \\\n\t\t\t\t\t\t      src, a, ##__VA_ARGS__)\n\n/*\n * BPF_CORE_READ_INTO() is a more performance-conscious variant of\n * BPF_CORE_READ(), in which final field is read into user-provided storage.\n * See BPF_CORE_READ() below for more details on general usage.\n */\n#define BPF_CORE_READ_INTO(dst, src, a, ...) ({\t\t\t\t    \\\n\t___core_read(bpf_core_read, bpf_core_read,\t\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ_INTO() for reading from user-space memory.\n *\n * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.\n */\n#define BPF_CORE_READ_USER_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_core_read_user, bpf_core_read_user,\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_INTO() */\n#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read, bpf_probe_read,\t\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_USER_INTO().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read_user, bpf_probe_read_user,\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * BPF_CORE_READ_STR_INTO() does same \"pointer chasing\" as\n * BPF_CORE_READ() for intermediate pointers, but then executes (and returns\n * corresponding error code) bpf_core_read_str() for final string read.\n */\n#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_core_read_str, bpf_core_read,\t\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ_STR_INTO() for reading from user-space memory.\n *\n * NOTE: see comments for BPF_CORE_READ_USER() about the proper types use.\n */\n#define BPF_CORE_READ_USER_STR_INTO(dst, src, a, ...) ({\t\t    \\\n\t___core_read(bpf_core_read_user_str, bpf_core_read_user,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ_STR_INTO() */\n#define BPF_PROBE_READ_STR_INTO(dst, src, a, ...) ({\t\t\t    \\\n\t___core_read(bpf_probe_read_str, bpf_probe_read,\t\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * Non-CO-RE variant of BPF_CORE_READ_USER_STR_INTO().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER_STR_INTO(dst, src, a, ...) ({\t\t    \\\n\t___core_read(bpf_probe_read_user_str, bpf_probe_read_user,\t    \\\n\t\t     dst, (src), a, ##__VA_ARGS__)\t\t\t    \\\n})\n\n/*\n * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially\n * when there are few pointer chasing steps.\n * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like:\n *\tint x = s->a.b.c->d.e->f->g;\n * can be succinctly achieved using BPF_CORE_READ as:\n *\tint x = BPF_CORE_READ(s, a.b.c, d.e, f, g);\n *\n * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF\n * CO-RE relocatable bpf_probe_read_kernel() wrapper) calls, logically\n * equivalent to:\n * 1. const void *__t = s->a.b.c;\n * 2. __t = __t->d.e;\n * 3. __t = __t->f;\n * 4. return __t->g;\n *\n * Equivalence is logical, because there is a heavy type casting/preservation\n * involved, as well as all the reads are happening through\n * bpf_probe_read_kernel() calls using __builtin_preserve_access_index() to\n * emit CO-RE relocations.\n *\n * N.B. Only up to 9 \"field accessors\" are supported, which should be more\n * than enough for any practical purpose.\n */\n#define BPF_CORE_READ(src, a, ...) ({\t\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/*\n * Variant of BPF_CORE_READ() for reading from user-space memory.\n *\n * NOTE: all the source types involved are still *kernel types* and need to\n * exist in kernel (or kernel module) BTF, otherwise CO-RE relocation will\n * fail. Custom user types are not relocatable with CO-RE.\n * The typical situation in which BPF_CORE_READ_USER() might be used is to\n * read kernel UAPI types from the user-space memory passed in as a syscall\n * input argument.\n */\n#define BPF_CORE_READ_USER(src, a, ...) ({\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_CORE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/* Non-CO-RE variant of BPF_CORE_READ() */\n#define BPF_PROBE_READ(src, a, ...) ({\t\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_PROBE_READ_INTO(&__r, (src), a, ##__VA_ARGS__);\t\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n/*\n * Non-CO-RE variant of BPF_CORE_READ_USER().\n *\n * As no CO-RE relocations are emitted, source types can be arbitrary and are\n * not restricted to kernel types only.\n */\n#define BPF_PROBE_READ_USER(src, a, ...) ({\t\t\t\t    \\\n\t___type((src), a, ##__VA_ARGS__) __r;\t\t\t\t    \\\n\tBPF_PROBE_READ_USER_INTO(&__r, (src), a, ##__VA_ARGS__);\t    \\\n\t__r;\t\t\t\t\t\t\t\t    \\\n})\n\n#endif\n\n"
  },
  {
    "path": "include/libbpf/bpf_endian.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_ENDIAN__\n#define __BPF_ENDIAN__\n\n/*\n * Isolate byte #n and put it into byte #m, for __u##b type.\n * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:\n * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx\n * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000\n * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn\n * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000\n */\n#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))\n\n#define ___bpf_swab16(x) ((__u16)(\t\t\t\\\n\t\t\t  ___bpf_mvb(x, 16, 0, 1) |\t\\\n\t\t\t  ___bpf_mvb(x, 16, 1, 0)))\n\n#define ___bpf_swab32(x) ((__u32)(\t\t\t\\\n\t\t\t  ___bpf_mvb(x, 32, 0, 3) |\t\\\n\t\t\t  ___bpf_mvb(x, 32, 1, 2) |\t\\\n\t\t\t  ___bpf_mvb(x, 32, 2, 1) |\t\\\n\t\t\t  ___bpf_mvb(x, 32, 3, 0)))\n\n#define ___bpf_swab64(x) ((__u64)(\t\t\t\\\n\t\t\t  ___bpf_mvb(x, 64, 0, 7) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 1, 6) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 2, 5) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 3, 4) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 4, 3) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 5, 2) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 6, 1) |\t\\\n\t\t\t  ___bpf_mvb(x, 64, 7, 0)))\n\n/* LLVM's BPF target selects the endianness of the CPU\n * it compiles on, or the user specifies (bpfel/bpfeb),\n * respectively. The used __BYTE_ORDER__ is defined by\n * the compiler, we cannot rely on __BYTE_ORDER from\n * libc headers, since it doesn't reflect the actual\n * requested byte order.\n *\n * Note, LLVM's BPF target has different __builtin_bswapX()\n * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE\n * in bpfel and bpfeb case, which means below, that we map\n * to cpu_to_be16(). We could use it unconditionally in BPF\n * case, but better not rely on it, so that this header here\n * can be used from application and BPF program side, which\n * use different targets.\n */\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n# define __bpf_ntohs(x)\t\t\t__builtin_bswap16(x)\n# define __bpf_htons(x)\t\t\t__builtin_bswap16(x)\n# define __bpf_constant_ntohs(x)\t___bpf_swab16(x)\n# define __bpf_constant_htons(x)\t___bpf_swab16(x)\n# define __bpf_ntohl(x)\t\t\t__builtin_bswap32(x)\n# define __bpf_htonl(x)\t\t\t__builtin_bswap32(x)\n# define __bpf_constant_ntohl(x)\t___bpf_swab32(x)\n# define __bpf_constant_htonl(x)\t___bpf_swab32(x)\n# define __bpf_be64_to_cpu(x)\t\t__builtin_bswap64(x)\n# define __bpf_cpu_to_be64(x)\t\t__builtin_bswap64(x)\n# define __bpf_constant_be64_to_cpu(x)\t___bpf_swab64(x)\n# define __bpf_constant_cpu_to_be64(x)\t___bpf_swab64(x)\n#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n# define __bpf_ntohs(x)\t\t\t(x)\n# define __bpf_htons(x)\t\t\t(x)\n# define __bpf_constant_ntohs(x)\t(x)\n# define __bpf_constant_htons(x)\t(x)\n# define __bpf_ntohl(x)\t\t\t(x)\n# define __bpf_htonl(x)\t\t\t(x)\n# define __bpf_constant_ntohl(x)\t(x)\n# define __bpf_constant_htonl(x)\t(x)\n# define __bpf_be64_to_cpu(x)\t\t(x)\n# define __bpf_cpu_to_be64(x)\t\t(x)\n# define __bpf_constant_be64_to_cpu(x)  (x)\n# define __bpf_constant_cpu_to_be64(x)  (x)\n#else\n# error \"Fix your compiler's __BYTE_ORDER__?!\"\n#endif\n\n#define bpf_htons(x)\t\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_htons(x) : __bpf_htons(x))\n#define bpf_ntohs(x)\t\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_ntohs(x) : __bpf_ntohs(x))\n#define bpf_htonl(x)\t\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_htonl(x) : __bpf_htonl(x))\n#define bpf_ntohl(x)\t\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_ntohl(x) : __bpf_ntohl(x))\n#define bpf_cpu_to_be64(x)\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))\n#define bpf_be64_to_cpu(x)\t\t\t\\\n\t(__builtin_constant_p(x) ?\t\t\\\n\t __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))\n\n#endif /* __BPF_ENDIAN__ */\n"
  },
  {
    "path": "include/libbpf/bpf_helper_defs.h",
    "content": "/* This is auto-generated file. See bpf_doc.py for details. */\n\n/* Forward declarations of BPF structs */\nstruct bpf_fib_lookup;\nstruct bpf_sk_lookup;\nstruct bpf_perf_event_data;\nstruct bpf_perf_event_value;\nstruct bpf_pidns_info;\nstruct bpf_redir_neigh;\nstruct bpf_sock;\nstruct bpf_sock_addr;\nstruct bpf_sock_ops;\nstruct bpf_sock_tuple;\nstruct bpf_spin_lock;\nstruct bpf_sysctl;\nstruct bpf_tcp_sock;\nstruct bpf_tunnel_key;\nstruct bpf_xfrm_state;\nstruct linux_binprm;\nstruct pt_regs;\nstruct sk_reuseport_md;\nstruct sockaddr;\nstruct tcphdr;\nstruct seq_file;\nstruct tcp6_sock;\nstruct tcp_sock;\nstruct tcp_timewait_sock;\nstruct tcp_request_sock;\nstruct udp6_sock;\nstruct task_struct;\nstruct __sk_buff;\nstruct sk_msg_md;\nstruct xdp_md;\nstruct path;\nstruct btf_ptr;\nstruct inode;\nstruct socket;\nstruct file;\nstruct bpf_timer;\n\n/*\n * bpf_map_lookup_elem\n *\n * \tPerform a lookup in *map* for an entry associated to *key*.\n *\n * Returns\n * \tMap value associated to *key*, or **NULL** if no entry was\n * \tfound.\n */\nstatic void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1;\n\n/*\n * bpf_map_update_elem\n *\n * \tAdd or update the value of the entry associated to *key* in\n * \t*map* with *value*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tFlag value **BPF_NOEXIST** cannot be used for maps of types\n * \t**BPF_MAP_TYPE_ARRAY** or **BPF_MAP_TYPE_PERCPU_ARRAY**  (all\n * \telements always exist), the helper would return an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_update_elem)(void *map, const void *key, const void *value, __u64 flags) = (void *) 2;\n\n/*\n * bpf_map_delete_elem\n *\n * \tDelete entry with *key* from *map*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_delete_elem)(void *map, const void *key) = (void *) 3;\n\n/*\n * bpf_probe_read\n *\n * \tFor tracing programs, safely attempt to read *size* bytes from\n * \tkernel space address *unsafe_ptr* and store the data in *dst*.\n *\n * \tGenerally, use **bpf_probe_read_user**\\ () or\n * \t**bpf_probe_read_kernel**\\ () instead.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 4;\n\n/*\n * bpf_ktime_get_ns\n *\n * \tReturn the time elapsed since system boot, in nanoseconds.\n * \tDoes not include time the system was suspended.\n * \tSee: **clock_gettime**\\ (**CLOCK_MONOTONIC**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_ns)(void) = (void *) 5;\n\n/*\n * bpf_trace_printk\n *\n * \tThis helper is a \"printk()-like\" facility for debugging. It\n * \tprints a message defined by format *fmt* (of size *fmt_size*)\n * \tto file *\\/sys/kernel/debug/tracing/trace* from DebugFS, if\n * \tavailable. It can take up to three additional **u64**\n * \targuments (as an eBPF helpers, the total number of arguments is\n * \tlimited to five).\n *\n * \tEach time the helper is called, it appends a line to the trace.\n * \tLines are discarded while *\\/sys/kernel/debug/tracing/trace* is\n * \topen, use *\\/sys/kernel/debug/tracing/trace_pipe* to avoid this.\n * \tThe format of the trace is customizable, and the exact output\n * \tone will get depends on the options set in\n * \t*\\/sys/kernel/debug/tracing/trace_options* (see also the\n * \t*README* file under the same directory). However, it usually\n * \tdefaults to something like:\n *\n * \t::\n *\n * \t\ttelnet-470   [001] .N.. 419421.045894: 0x00000001: <formatted msg>\n *\n * \tIn the above:\n *\n * \t\t* ``telnet`` is the name of the current task.\n * \t\t* ``470`` is the PID of the current task.\n * \t\t* ``001`` is the CPU number on which the task is\n * \t\t  running.\n * \t\t* In ``.N..``, each character refers to a set of\n * \t\t  options (whether irqs are enabled, scheduling\n * \t\t  options, whether hard/softirqs are running, level of\n * \t\t  preempt_disabled respectively). **N** means that\n * \t\t  **TIF_NEED_RESCHED** and **PREEMPT_NEED_RESCHED**\n * \t\t  are set.\n * \t\t* ``419421.045894`` is a timestamp.\n * \t\t* ``0x00000001`` is a fake value used by BPF for the\n * \t\t  instruction pointer register.\n * \t\t* ``<formatted msg>`` is the message formatted with\n * \t\t  *fmt*.\n *\n * \tThe conversion specifiers supported by *fmt* are similar, but\n * \tmore limited than for printk(). They are **%d**, **%i**,\n * \t**%u**, **%x**, **%ld**, **%li**, **%lu**, **%lx**, **%lld**,\n * \t**%lli**, **%llu**, **%llx**, **%p**, **%s**. No modifier (size\n * \tof field, padding with zeroes, etc.) is available, and the\n * \thelper will return **-EINVAL** (but print nothing) if it\n * \tencounters an unknown specifier.\n *\n * \tAlso, note that **bpf_trace_printk**\\ () is slow, and should\n * \tonly be used for debugging purposes. For this reason, a notice\n * \tblock (spanning several lines) is printed to kernel logs and\n * \tstates that the helper should not be used \"for production use\"\n * \tthe first time this helper is used (or more precisely, when\n * \t**trace_printk**\\ () buffers are allocated). For passing values\n * \tto user space, perf events should be preferred.\n *\n * Returns\n * \tThe number of bytes written to the buffer, or a negative error\n * \tin case of failure.\n */\nstatic long (*bpf_trace_printk)(const char *fmt, __u32 fmt_size, ...) = (void *) 6;\n\n/*\n * bpf_get_prandom_u32\n *\n * \tGet a pseudo-random number.\n *\n * \tFrom a security point of view, this helper uses its own\n * \tpseudo-random internal state, and cannot be used to infer the\n * \tseed of other random functions in the kernel. However, it is\n * \tessential to note that the generator used by the helper is not\n * \tcryptographically secure.\n *\n * Returns\n * \tA random 32-bit unsigned value.\n */\nstatic __u32 (*bpf_get_prandom_u32)(void) = (void *) 7;\n\n/*\n * bpf_get_smp_processor_id\n *\n * \tGet the SMP (symmetric multiprocessing) processor id. Note that\n * \tall programs run with preemption disabled, which means that the\n * \tSMP processor id is stable during all the execution of the\n * \tprogram.\n *\n * Returns\n * \tThe SMP id of the processor running the program.\n */\nstatic __u32 (*bpf_get_smp_processor_id)(void) = (void *) 8;\n\n/*\n * bpf_skb_store_bytes\n *\n * \tStore *len* bytes from address *from* into the packet\n * \tassociated to *skb*, at *offset*. *flags* are a combination of\n * \t**BPF_F_RECOMPUTE_CSUM** (automatically recompute the\n * \tchecksum for the packet after storing the bytes) and\n * \t**BPF_F_INVALIDATE_HASH** (set *skb*\\ **->hash**, *skb*\\\n * \t**->swhash** and *skb*\\ **->l4hash** to 0).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len, __u64 flags) = (void *) 9;\n\n/*\n * bpf_l3_csum_replace\n *\n * \tRecompute the layer 3 (e.g. IP) checksum for the packet\n * \tassociated to *skb*. Computation is incremental, so the helper\n * \tmust know the former value of the header field that was\n * \tmodified (*from*), the new value of this field (*to*), and the\n * \tnumber of bytes (2 or 4) for this field, stored in *size*.\n * \tAlternatively, it is possible to store the difference between\n * \tthe previous and the new values of the header field in *to*, by\n * \tsetting *from* and *size* to 0. For both methods, *offset*\n * \tindicates the location of the IP checksum within the packet.\n *\n * \tThis helper works in combination with **bpf_csum_diff**\\ (),\n * \twhich does not update the checksum in-place, but offers more\n * \tflexibility and can handle sizes larger than 2 or 4 for the\n * \tchecksum to update.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_l3_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 size) = (void *) 10;\n\n/*\n * bpf_l4_csum_replace\n *\n * \tRecompute the layer 4 (e.g. TCP, UDP or ICMP) checksum for the\n * \tpacket associated to *skb*. Computation is incremental, so the\n * \thelper must know the former value of the header field that was\n * \tmodified (*from*), the new value of this field (*to*), and the\n * \tnumber of bytes (2 or 4) for this field, stored on the lowest\n * \tfour bits of *flags*. Alternatively, it is possible to store\n * \tthe difference between the previous and the new values of the\n * \theader field in *to*, by setting *from* and the four lowest\n * \tbits of *flags* to 0. For both methods, *offset* indicates the\n * \tlocation of the IP checksum within the packet. In addition to\n * \tthe size of the field, *flags* can be added (bitwise OR) actual\n * \tflags. With **BPF_F_MARK_MANGLED_0**, a null checksum is left\n * \tuntouched (unless **BPF_F_MARK_ENFORCE** is added as well), and\n * \tfor updates resulting in a null checksum the value is set to\n * \t**CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates\n * \tthe checksum is to be computed against a pseudo-header.\n *\n * \tThis helper works in combination with **bpf_csum_diff**\\ (),\n * \twhich does not update the checksum in-place, but offers more\n * \tflexibility and can handle sizes larger than 2 or 4 for the\n * \tchecksum to update.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_l4_csum_replace)(struct __sk_buff *skb, __u32 offset, __u64 from, __u64 to, __u64 flags) = (void *) 11;\n\n/*\n * bpf_tail_call\n *\n * \tThis special helper is used to trigger a \"tail call\", or in\n * \tother words, to jump into another eBPF program. The same stack\n * \tframe is used (but values on stack and in registers for the\n * \tcaller are not accessible to the callee). This mechanism allows\n * \tfor program chaining, either for raising the maximum number of\n * \tavailable eBPF instructions, or to execute given programs in\n * \tconditional blocks. For security reasons, there is an upper\n * \tlimit to the number of successive tail calls that can be\n * \tperformed.\n *\n * \tUpon call of this helper, the program attempts to jump into a\n * \tprogram referenced at index *index* in *prog_array_map*, a\n * \tspecial map of type **BPF_MAP_TYPE_PROG_ARRAY**, and passes\n * \t*ctx*, a pointer to the context.\n *\n * \tIf the call succeeds, the kernel immediately runs the first\n * \tinstruction of the new program. This is not a function call,\n * \tand it never returns to the previous program. If the call\n * \tfails, then the helper has no effect, and the caller continues\n * \tto run its subsequent instructions. A call can fail if the\n * \tdestination program for the jump does not exist (i.e. *index*\n * \tis superior to the number of entries in *prog_array_map*), or\n * \tif the maximum number of tail calls has been reached for this\n * \tchain of programs. This limit is defined in the kernel by the\n * \tmacro **MAX_TAIL_CALL_CNT** (not accessible to user space),\n * \twhich is currently set to 32.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_tail_call)(void *ctx, void *prog_array_map, __u32 index) = (void *) 12;\n\n/*\n * bpf_clone_redirect\n *\n * \tClone and redirect the packet associated to *skb* to another\n * \tnet device of index *ifindex*. Both ingress and egress\n * \tinterfaces can be used for redirection. The **BPF_F_INGRESS**\n * \tvalue in *flags* is used to make the distinction (ingress path\n * \tis selected if the flag is present, egress path otherwise).\n * \tThis is the only flag supported for now.\n *\n * \tIn comparison with **bpf_redirect**\\ () helper,\n * \t**bpf_clone_redirect**\\ () has the associated cost of\n * \tduplicating the packet buffer, but this can be executed out of\n * \tthe eBPF program. Conversely, **bpf_redirect**\\ () is more\n * \tefficient, but it is handled through an action code where the\n * \tredirection happens only after the eBPF program has returned.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_clone_redirect)(struct __sk_buff *skb, __u32 ifindex, __u64 flags) = (void *) 13;\n\n/*\n * bpf_get_current_pid_tgid\n *\n *\n * Returns\n * \tA 64-bit integer containing the current tgid and pid, and\n * \tcreated as such:\n * \t*current_task*\\ **->tgid << 32 \\|**\n * \t*current_task*\\ **->pid**.\n */\nstatic __u64 (*bpf_get_current_pid_tgid)(void) = (void *) 14;\n\n/*\n * bpf_get_current_uid_gid\n *\n *\n * Returns\n * \tA 64-bit integer containing the current GID and UID, and\n * \tcreated as such: *current_gid* **<< 32 \\|** *current_uid*.\n */\nstatic __u64 (*bpf_get_current_uid_gid)(void) = (void *) 15;\n\n/*\n * bpf_get_current_comm\n *\n * \tCopy the **comm** attribute of the current task into *buf* of\n * \t*size_of_buf*. The **comm** attribute contains the name of\n * \tthe executable (excluding the path) for the current task. The\n * \t*size_of_buf* must be strictly positive. On success, the\n * \thelper makes sure that the *buf* is NUL-terminated. On failure,\n * \tit is filled with zeroes.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_get_current_comm)(void *buf, __u32 size_of_buf) = (void *) 16;\n\n/*\n * bpf_get_cgroup_classid\n *\n * \tRetrieve the classid for the current task, i.e. for the net_cls\n * \tcgroup to which *skb* belongs.\n *\n * \tThis helper can be used on TC egress path, but not on ingress.\n *\n * \tThe net_cls cgroup provides an interface to tag network packets\n * \tbased on a user-provided identifier for all traffic coming from\n * \tthe tasks belonging to the related cgroup. See also the related\n * \tkernel documentation, available from the Linux sources in file\n * \t*Documentation/admin-guide/cgroup-v1/net_cls.rst*.\n *\n * \tThe Linux kernel has two versions for cgroups: there are\n * \tcgroups v1 and cgroups v2. Both are available to users, who can\n * \tuse a mixture of them, but note that the net_cls cgroup is for\n * \tcgroup v1 only. This makes it incompatible with BPF programs\n * \trun on cgroups, which is a cgroup-v2-only feature (a socket can\n * \tonly hold data for one version of cgroups at a time).\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_CGROUP_NET_CLASSID** configuration option set to\n * \t\"**y**\" or to \"**m**\".\n *\n * Returns\n * \tThe classid, or 0 for the default unconfigured classid.\n */\nstatic __u32 (*bpf_get_cgroup_classid)(struct __sk_buff *skb) = (void *) 17;\n\n/*\n * bpf_skb_vlan_push\n *\n * \tPush a *vlan_tci* (VLAN tag control information) of protocol\n * \t*vlan_proto* to the packet associated to *skb*, then update\n * \tthe checksum. Note that if *vlan_proto* is different from\n * \t**ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to\n * \tbe **ETH_P_8021Q**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_vlan_push)(struct __sk_buff *skb, __be16 vlan_proto, __u16 vlan_tci) = (void *) 18;\n\n/*\n * bpf_skb_vlan_pop\n *\n * \tPop a VLAN header from the packet associated to *skb*.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_vlan_pop)(struct __sk_buff *skb) = (void *) 19;\n\n/*\n * bpf_skb_get_tunnel_key\n *\n * \tGet tunnel metadata. This helper takes a pointer *key* to an\n * \tempty **struct bpf_tunnel_key** of **size**, that will be\n * \tfilled with tunnel metadata for the packet associated to *skb*.\n * \tThe *flags* can be set to **BPF_F_TUNINFO_IPV6**, which\n * \tindicates that the tunnel is based on IPv6 protocol instead of\n * \tIPv4.\n *\n * \tThe **struct bpf_tunnel_key** is an object that generalizes the\n * \tprincipal parameters used by various tunneling protocols into a\n * \tsingle struct. This way, it can be used to easily make a\n * \tdecision based on the contents of the encapsulation header,\n * \t\"summarized\" in this struct. In particular, it holds the IP\n * \taddress of the remote end (IPv4 or IPv6, depending on the case)\n * \tin *key*\\ **->remote_ipv4** or *key*\\ **->remote_ipv6**. Also,\n * \tthis struct exposes the *key*\\ **->tunnel_id**, which is\n * \tgenerally mapped to a VNI (Virtual Network Identifier), making\n * \tit programmable together with the **bpf_skb_set_tunnel_key**\\\n * \t() helper.\n *\n * \tLet's imagine that the following code is part of a program\n * \tattached to the TC ingress interface, on one end of a GRE\n * \ttunnel, and is supposed to filter out all messages coming from\n * \tremote ends with IPv4 address other than 10.0.0.1:\n *\n * \t::\n *\n * \t\tint ret;\n * \t\tstruct bpf_tunnel_key key = {};\n *\n * \t\tret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);\n * \t\tif (ret < 0)\n * \t\t\treturn TC_ACT_SHOT;\t// drop packet\n *\n * \t\tif (key.remote_ipv4 != 0x0a000001)\n * \t\t\treturn TC_ACT_SHOT;\t// drop packet\n *\n * \t\treturn TC_ACT_OK;\t\t// accept packet\n *\n * \tThis interface can also be used with all encapsulation devices\n * \tthat can operate in \"collect metadata\" mode: instead of having\n * \tone network device per specific configuration, the \"collect\n * \tmetadata\" mode only requires a single device where the\n * \tconfiguration can be extracted from this helper.\n *\n * \tThis can be used together with various tunnels such as VXLan,\n * \tGeneve, GRE or IP in IP (IPIP).\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_get_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 20;\n\n/*\n * bpf_skb_set_tunnel_key\n *\n * \tPopulate tunnel metadata for packet associated to *skb.* The\n * \ttunnel metadata is set to the contents of *key*, of *size*. The\n * \t*flags* can be set to a combination of the following values:\n *\n * \t**BPF_F_TUNINFO_IPV6**\n * \t\tIndicate that the tunnel is based on IPv6 protocol\n * \t\tinstead of IPv4.\n * \t**BPF_F_ZERO_CSUM_TX**\n * \t\tFor IPv4 packets, add a flag to tunnel metadata\n * \t\tindicating that checksum computation should be skipped\n * \t\tand checksum set to zeroes.\n * \t**BPF_F_DONT_FRAGMENT**\n * \t\tAdd a flag to tunnel metadata indicating that the\n * \t\tpacket should not be fragmented.\n * \t**BPF_F_SEQ_NUMBER**\n * \t\tAdd a flag to tunnel metadata indicating that a\n * \t\tsequence number should be added to tunnel header before\n * \t\tsending the packet. This flag was added for GRE\n * \t\tencapsulation, but might be used with other protocols\n * \t\tas well in the future.\n *\n * \tHere is a typical usage on the transmit path:\n *\n * \t::\n *\n * \t\tstruct bpf_tunnel_key key;\n * \t\t     populate key ...\n * \t\tbpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0);\n * \t\tbpf_clone_redirect(skb, vxlan_dev_ifindex, 0);\n *\n * \tSee also the description of the **bpf_skb_get_tunnel_key**\\ ()\n * \thelper for additional information.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_set_tunnel_key)(struct __sk_buff *skb, struct bpf_tunnel_key *key, __u32 size, __u64 flags) = (void *) 21;\n\n/*\n * bpf_perf_event_read\n *\n * \tRead the value of a perf event counter. This helper relies on a\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of\n * \tthe perf event counter is selected when *map* is updated with\n * \tperf event file descriptors. The *map* is an array whose size\n * \tis the number of available CPUs, and each cell contains a value\n * \trelative to one CPU. The value to retrieve is indicated by\n * \t*flags*, that contains the index of the CPU to look up, masked\n * \twith **BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to\n * \t**BPF_F_CURRENT_CPU** to indicate that the value for the\n * \tcurrent CPU should be retrieved.\n *\n * \tNote that before Linux 4.13, only hardware perf event can be\n * \tretrieved.\n *\n * \tAlso, be aware that the newer helper\n * \t**bpf_perf_event_read_value**\\ () is recommended over\n * \t**bpf_perf_event_read**\\ () in general. The latter has some ABI\n * \tquirks where error and counter value are used as a return code\n * \t(which is wrong to do since ranges may overlap). This issue is\n * \tfixed with **bpf_perf_event_read_value**\\ (), which at the same\n * \ttime provides more features over the **bpf_perf_event_read**\\\n * \t() interface. Please refer to the description of\n * \t**bpf_perf_event_read_value**\\ () for details.\n *\n * Returns\n * \tThe value of the perf event counter read from the map, or a\n * \tnegative error code in case of failure.\n */\nstatic __u64 (*bpf_perf_event_read)(void *map, __u64 flags) = (void *) 22;\n\n/*\n * bpf_redirect\n *\n * \tRedirect the packet to another net device of index *ifindex*.\n * \tThis helper is somewhat similar to **bpf_clone_redirect**\\\n * \t(), except that the packet is not cloned, which provides\n * \tincreased performance.\n *\n * \tExcept for XDP, both ingress and egress interfaces can be used\n * \tfor redirection. The **BPF_F_INGRESS** value in *flags* is used\n * \tto make the distinction (ingress path is selected if the flag\n * \tis present, egress path otherwise). Currently, XDP only\n * \tsupports redirection to the egress interface, and accepts no\n * \tflag at all.\n *\n * \tThe same effect can also be attained with the more generic\n * \t**bpf_redirect_map**\\ (), which uses a BPF map to store the\n * \tredirect target instead of providing it directly to the helper.\n *\n * Returns\n * \tFor XDP, the helper returns **XDP_REDIRECT** on success or\n * \t**XDP_ABORTED** on error. For other program types, the values\n * \tare **TC_ACT_REDIRECT** on success or **TC_ACT_SHOT** on\n * \terror.\n */\nstatic long (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void *) 23;\n\n/*\n * bpf_get_route_realm\n *\n * \tRetrieve the realm or the route, that is to say the\n * \t**tclassid** field of the destination for the *skb*. The\n * \tidentifier retrieved is a user-provided tag, similar to the\n * \tone used with the net_cls cgroup (see description for\n * \t**bpf_get_cgroup_classid**\\ () helper), but here this tag is\n * \theld by a route (a destination entry), not by a task.\n *\n * \tRetrieving this identifier works with the clsact TC egress hook\n * \t(see also **tc-bpf(8)**), or alternatively on conventional\n * \tclassful egress qdiscs, but not on TC ingress path. In case of\n * \tclsact TC egress hook, this has the advantage that, internally,\n * \tthe destination entry has not been dropped yet in the transmit\n * \tpath. Therefore, the destination entry does not need to be\n * \tartificially held via **netif_keep_dst**\\ () for a classful\n * \tqdisc until the *skb* is freed.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_IP_ROUTE_CLASSID** configuration option.\n *\n * Returns\n * \tThe realm of the route for the packet associated to *skb*, or 0\n * \tif none was found.\n */\nstatic __u32 (*bpf_get_route_realm)(struct __sk_buff *skb) = (void *) 24;\n\n/*\n * bpf_perf_event_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \tThe context of the program *ctx* needs also be passed to the\n * \thelper.\n *\n * \tOn user space, a program willing to read the values needs to\n * \tcall **perf_event_open**\\ () on the perf event (either for\n * \tone or for all CPUs) and to store the file descriptor into the\n * \t*map*. This must be done before the eBPF program can send data\n * \tinto it. An example is available in file\n * \t*samples/bpf/trace_output_user.c* in the Linux kernel source\n * \ttree (the eBPF program counterpart is in\n * \t*samples/bpf/trace_output_kern.c*).\n *\n * \t**bpf_perf_event_output**\\ () achieves better performance\n * \tthan **bpf_trace_printk**\\ () for sharing data with user\n * \tspace, and is much better suitable for streaming data from eBPF\n * \tprograms.\n *\n * \tNote that this helper is not restricted to tracing use cases\n * \tand can be used with programs attached to TC or XDP as well,\n * \twhere it allows for passing data to user space listeners. Data\n * \tcan be:\n *\n * \t* Only custom structs,\n * \t* Only the packet payload, or\n * \t* A combination of both.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_event_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 25;\n\n/*\n * bpf_skb_load_bytes\n *\n * \tThis helper was provided as an easy way to load data from a\n * \tpacket. It can be used to load *len* bytes from *offset* from\n * \tthe packet associated to *skb*, into the buffer pointed by\n * \t*to*.\n *\n * \tSince Linux 4.7, usage of this helper has mostly been replaced\n * \tby \"direct packet access\", enabling packet data to be\n * \tmanipulated with *skb*\\ **->data** and *skb*\\ **->data_end**\n * \tpointing respectively to the first byte of packet data and to\n * \tthe byte after the last byte of packet data. However, it\n * \tremains useful if one wishes to read large quantities of data\n * \tat once from a packet into the eBPF stack.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_load_bytes)(const void *skb, __u32 offset, void *to, __u32 len) = (void *) 26;\n\n/*\n * bpf_get_stackid\n *\n * \tWalk a user or a kernel stack and return its id. To achieve\n * \tthis, the helper needs *ctx*, which is a pointer to the context\n * \ton which the tracing program is executed, and a pointer to a\n * \t*map* of type **BPF_MAP_TYPE_STACK_TRACE**.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \ta combination of the following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_FAST_STACK_CMP**\n * \t\tCompare stacks by hash only.\n * \t**BPF_F_REUSE_STACKID**\n * \t\tIf two different stacks hash into the same *stackid*,\n * \t\tdiscard the old one.\n *\n * \tThe stack id retrieved is a 32 bit long integer handle which\n * \tcan be further combined with other data (including other stack\n * \tids) and used as a key into maps. This can be useful for\n * \tgenerating a variety of graphs (such as flame graphs or off-cpu\n * \tgraphs).\n *\n * \tFor walking a stack, this helper is an improvement over\n * \t**bpf_probe_read**\\ (), which can be used with unrolled loops\n * \tbut is not efficient and consumes a lot of eBPF instructions.\n * \tInstead, **bpf_get_stackid**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tThe positive or null stack id on success, or a negative error\n * \tin case of failure.\n */\nstatic long (*bpf_get_stackid)(void *ctx, void *map, __u64 flags) = (void *) 27;\n\n/*\n * bpf_csum_diff\n *\n * \tCompute a checksum difference, from the raw buffer pointed by\n * \t*from*, of length *from_size* (that must be a multiple of 4),\n * \ttowards the raw buffer pointed by *to*, of size *to_size*\n * \t(same remark). An optional *seed* can be added to the value\n * \t(this can be cascaded, the seed may come from a previous call\n * \tto the helper).\n *\n * \tThis is flexible enough to be used in several ways:\n *\n * \t* With *from_size* == 0, *to_size* > 0 and *seed* set to\n * \t  checksum, it can be used when pushing new data.\n * \t* With *from_size* > 0, *to_size* == 0 and *seed* set to\n * \t  checksum, it can be used when removing data from a packet.\n * \t* With *from_size* > 0, *to_size* > 0 and *seed* set to 0, it\n * \t  can be used to compute a diff. Note that *from_size* and\n * \t  *to_size* do not need to be equal.\n *\n * \tThis helper can be used in combination with\n * \t**bpf_l3_csum_replace**\\ () and **bpf_l4_csum_replace**\\ (), to\n * \twhich one can feed in the difference computed with\n * \t**bpf_csum_diff**\\ ().\n *\n * Returns\n * \tThe checksum result, or a negative error code in case of\n * \tfailure.\n */\nstatic __s64 (*bpf_csum_diff)(__be32 *from, __u32 from_size, __be32 *to, __u32 to_size, __wsum seed) = (void *) 28;\n\n/*\n * bpf_skb_get_tunnel_opt\n *\n * \tRetrieve tunnel options metadata for the packet associated to\n * \t*skb*, and store the raw tunnel option data to the buffer *opt*\n * \tof *size*.\n *\n * \tThis helper can be used with encapsulation devices that can\n * \toperate in \"collect metadata\" mode (please refer to the related\n * \tnote in the description of **bpf_skb_get_tunnel_key**\\ () for\n * \tmore details). A particular example where this can be used is\n * \tin combination with the Geneve encapsulation protocol, where it\n * \tallows for pushing (with **bpf_skb_get_tunnel_opt**\\ () helper)\n * \tand retrieving arbitrary TLVs (Type-Length-Value headers) from\n * \tthe eBPF program. This allows for full customization of these\n * \theaders.\n *\n * Returns\n * \tThe size of the option data retrieved.\n */\nstatic long (*bpf_skb_get_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 29;\n\n/*\n * bpf_skb_set_tunnel_opt\n *\n * \tSet tunnel options metadata for the packet associated to *skb*\n * \tto the option data contained in the raw buffer *opt* of *size*.\n *\n * \tSee also the description of the **bpf_skb_get_tunnel_opt**\\ ()\n * \thelper for additional information.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_set_tunnel_opt)(struct __sk_buff *skb, void *opt, __u32 size) = (void *) 30;\n\n/*\n * bpf_skb_change_proto\n *\n * \tChange the protocol of the *skb* to *proto*. Currently\n * \tsupported are transition from IPv4 to IPv6, and from IPv6 to\n * \tIPv4. The helper takes care of the groundwork for the\n * \ttransition, including resizing the socket buffer. The eBPF\n * \tprogram is expected to fill the new headers, if any, via\n * \t**skb_store_bytes**\\ () and to recompute the checksums with\n * \t**bpf_l3_csum_replace**\\ () and **bpf_l4_csum_replace**\\\n * \t(). The main case for this helper is to perform NAT64\n * \toperations out of an eBPF program.\n *\n * \tInternally, the GSO type is marked as dodgy so that headers are\n * \tchecked and segments are recalculated by the GSO/GRO engine.\n * \tThe size for GSO target is adapted as well.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_proto)(struct __sk_buff *skb, __be16 proto, __u64 flags) = (void *) 31;\n\n/*\n * bpf_skb_change_type\n *\n * \tChange the packet type for the packet associated to *skb*. This\n * \tcomes down to setting *skb*\\ **->pkt_type** to *type*, except\n * \tthe eBPF program does not have a write access to *skb*\\\n * \t**->pkt_type** beside this helper. Using a helper here allows\n * \tfor graceful handling of errors.\n *\n * \tThe major use case is to change incoming *skb*s to\n * \t**PACKET_HOST** in a programmatic way instead of having to\n * \trecirculate via **redirect**\\ (..., **BPF_F_INGRESS**), for\n * \texample.\n *\n * \tNote that *type* only allows certain values. At this time, they\n * \tare:\n *\n * \t**PACKET_HOST**\n * \t\tPacket is for us.\n * \t**PACKET_BROADCAST**\n * \t\tSend packet to all.\n * \t**PACKET_MULTICAST**\n * \t\tSend packet to group.\n * \t**PACKET_OTHERHOST**\n * \t\tSend packet to someone else.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_type)(struct __sk_buff *skb, __u32 type) = (void *) 32;\n\n/*\n * bpf_skb_under_cgroup\n *\n * \tCheck whether *skb* is a descendant of the cgroup2 held by\n * \t*map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*.\n *\n * Returns\n * \tThe return value depends on the result of the test, and can be:\n *\n * \t* 0, if the *skb* failed the cgroup2 descendant test.\n * \t* 1, if the *skb* succeeded the cgroup2 descendant test.\n * \t* A negative error code, if an error occurred.\n */\nstatic long (*bpf_skb_under_cgroup)(struct __sk_buff *skb, void *map, __u32 index) = (void *) 33;\n\n/*\n * bpf_get_hash_recalc\n *\n * \tRetrieve the hash of the packet, *skb*\\ **->hash**. If it is\n * \tnot set, in particular if the hash was cleared due to mangling,\n * \trecompute this hash. Later accesses to the hash can be done\n * \tdirectly with *skb*\\ **->hash**.\n *\n * \tCalling **bpf_set_hash_invalid**\\ (), changing a packet\n * \tprototype with **bpf_skb_change_proto**\\ (), or calling\n * \t**bpf_skb_store_bytes**\\ () with the\n * \t**BPF_F_INVALIDATE_HASH** are actions susceptible to clear\n * \tthe hash and to trigger a new computation for the next call to\n * \t**bpf_get_hash_recalc**\\ ().\n *\n * Returns\n * \tThe 32-bit hash.\n */\nstatic __u32 (*bpf_get_hash_recalc)(struct __sk_buff *skb) = (void *) 34;\n\n/*\n * bpf_get_current_task\n *\n *\n * Returns\n * \tA pointer to the current task struct.\n */\nstatic __u64 (*bpf_get_current_task)(void) = (void *) 35;\n\n/*\n * bpf_probe_write_user\n *\n * \tAttempt in a safe way to write *len* bytes from the buffer\n * \t*src* to *dst* in memory. It only works for threads that are in\n * \tuser context, and *dst* must be a valid user space address.\n *\n * \tThis helper should not be used to implement any kind of\n * \tsecurity mechanism because of TOC-TOU attacks, but rather to\n * \tdebug, divert, and manipulate execution of semi-cooperative\n * \tprocesses.\n *\n * \tKeep in mind that this feature is meant for experiments, and it\n * \thas a risk of crashing the system and running programs.\n * \tTherefore, when an eBPF program using this helper is attached,\n * \ta warning including PID and process name is printed to kernel\n * \tlogs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_write_user)(void *dst, const void *src, __u32 len) = (void *) 36;\n\n/*\n * bpf_current_task_under_cgroup\n *\n * \tCheck whether the probe is being run is the context of a given\n * \tsubset of the cgroup2 hierarchy. The cgroup2 to test is held by\n * \t*map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*.\n *\n * Returns\n * \tThe return value depends on the result of the test, and can be:\n *\n * \t* 0, if current task belongs to the cgroup2.\n * \t* 1, if current task does not belong to the cgroup2.\n * \t* A negative error code, if an error occurred.\n */\nstatic long (*bpf_current_task_under_cgroup)(void *map, __u32 index) = (void *) 37;\n\n/*\n * bpf_skb_change_tail\n *\n * \tResize (trim or grow) the packet associated to *skb* to the\n * \tnew *len*. The *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThe basic idea is that the helper performs the needed work to\n * \tchange the size of the packet, then the eBPF program rewrites\n * \tthe rest via helpers like **bpf_skb_store_bytes**\\ (),\n * \t**bpf_l3_csum_replace**\\ (), **bpf_l3_csum_replace**\\ ()\n * \tand others. This helper is a slow path utility intended for\n * \treplies with control messages. And because it is targeted for\n * \tslow path, the helper itself can afford to be slow: it\n * \timplicitly linearizes, unclones and drops offloads from the\n * \t*skb*.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_tail)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 38;\n\n/*\n * bpf_skb_pull_data\n *\n * \tPull in non-linear data in case the *skb* is non-linear and not\n * \tall of *len* are part of the linear section. Make *len* bytes\n * \tfrom *skb* readable and writable. If a zero value is passed for\n * \t*len*, then the whole length of the *skb* is pulled.\n *\n * \tThis helper is only needed for reading and writing with direct\n * \tpacket access.\n *\n * \tFor direct packet access, testing that offsets to access\n * \tare within packet boundaries (test on *skb*\\ **->data_end**) is\n * \tsusceptible to fail if offsets are invalid, or if the requested\n * \tdata is in non-linear parts of the *skb*. On failure the\n * \tprogram can just bail out, or in the case of a non-linear\n * \tbuffer, use a helper to make the data available. The\n * \t**bpf_skb_load_bytes**\\ () helper is a first solution to access\n * \tthe data. Another one consists in using **bpf_skb_pull_data**\n * \tto pull in once the non-linear parts, then retesting and\n * \teventually access the data.\n *\n * \tAt the same time, this also makes sure the *skb* is uncloned,\n * \twhich is a necessary condition for direct write. As this needs\n * \tto be an invariant for the write part only, the verifier\n * \tdetects writes and adds a prologue that is calling\n * \t**bpf_skb_pull_data()** to effectively unclone the *skb* from\n * \tthe very beginning in case it is indeed cloned.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_pull_data)(struct __sk_buff *skb, __u32 len) = (void *) 39;\n\n/*\n * bpf_csum_update\n *\n * \tAdd the checksum *csum* into *skb*\\ **->csum** in case the\n * \tdriver has supplied a checksum for the entire packet into that\n * \tfield. Return an error otherwise. This helper is intended to be\n * \tused in combination with **bpf_csum_diff**\\ (), in particular\n * \twhen the checksum needs to be updated after data has been\n * \twritten into the packet through direct packet access.\n *\n * Returns\n * \tThe checksum on success, or a negative error code in case of\n * \tfailure.\n */\nstatic __s64 (*bpf_csum_update)(struct __sk_buff *skb, __wsum csum) = (void *) 40;\n\n/*\n * bpf_set_hash_invalid\n *\n * \tInvalidate the current *skb*\\ **->hash**. It can be used after\n * \tmangling on headers through direct packet access, in order to\n * \tindicate that the hash is outdated and to trigger a\n * \trecalculation the next time the kernel tries to access this\n * \thash or when the **bpf_get_hash_recalc**\\ () helper is called.\n *\n */\nstatic void (*bpf_set_hash_invalid)(struct __sk_buff *skb) = (void *) 41;\n\n/*\n * bpf_get_numa_node_id\n *\n * \tReturn the id of the current NUMA node. The primary use case\n * \tfor this helper is the selection of sockets for the local NUMA\n * \tnode, when the program is attached to sockets using the\n * \t**SO_ATTACH_REUSEPORT_EBPF** option (see also **socket(7)**),\n * \tbut the helper is also available to other eBPF program types,\n * \tsimilarly to **bpf_get_smp_processor_id**\\ ().\n *\n * Returns\n * \tThe id of current NUMA node.\n */\nstatic long (*bpf_get_numa_node_id)(void) = (void *) 42;\n\n/*\n * bpf_skb_change_head\n *\n * \tGrows headroom of packet associated to *skb* and adjusts the\n * \toffset of the MAC header accordingly, adding *len* bytes of\n * \tspace. It automatically extends and reallocates memory as\n * \trequired.\n *\n * \tThis helper can be used on a layer 3 *skb* to push a MAC header\n * \tfor redirection into a layer 2 device.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_change_head)(struct __sk_buff *skb, __u32 len, __u64 flags) = (void *) 43;\n\n/*\n * bpf_xdp_adjust_head\n *\n * \tAdjust (move) *xdp_md*\\ **->data** by *delta* bytes. Note that\n * \tit is possible to use a negative value for *delta*. This helper\n * \tcan be used to prepare the packet for pushing or popping\n * \theaders.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_head)(struct xdp_md *xdp_md, int delta) = (void *) 44;\n\n/*\n * bpf_probe_read_str\n *\n * \tCopy a NUL terminated string from an unsafe kernel address\n * \t*unsafe_ptr* to *dst*. See **bpf_probe_read_kernel_str**\\ () for\n * \tmore details.\n *\n * \tGenerally, use **bpf_probe_read_user_str**\\ () or\n * \t**bpf_probe_read_kernel_str**\\ () instead.\n *\n * Returns\n * \tOn success, the strictly positive length of the string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_probe_read_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 45;\n\n/*\n * bpf_get_socket_cookie\n *\n * \tIf the **struct sk_buff** pointed by *skb* has a known socket,\n * \tretrieve the cookie (generated by the kernel) of this socket.\n * \tIf no cookie has been set yet, generate a new cookie. Once\n * \tgenerated, the socket cookie remains stable for the life of the\n * \tsocket. This helper can be useful for monitoring per socket\n * \tnetworking traffic statistics as it provides a global socket\n * \tidentifier that can be assumed unique.\n *\n * Returns\n * \tA 8-byte long unique number on success, or 0 if the socket\n * \tfield is missing inside *skb*.\n */\nstatic __u64 (*bpf_get_socket_cookie)(void *ctx) = (void *) 46;\n\n/*\n * bpf_get_socket_uid\n *\n *\n * Returns\n * \tThe owner UID of the socket associated to *skb*. If the socket\n * \tis **NULL**, or if it is not a full socket (i.e. if it is a\n * \ttime-wait or a request socket instead), **overflowuid** value\n * \tis returned (note that **overflowuid** might also be the actual\n * \tUID value for the socket).\n */\nstatic __u32 (*bpf_get_socket_uid)(struct __sk_buff *skb) = (void *) 47;\n\n/*\n * bpf_set_hash\n *\n * \tSet the full hash for *skb* (set the field *skb*\\ **->hash**)\n * \tto value *hash*.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_set_hash)(struct __sk_buff *skb, __u32 hash) = (void *) 48;\n\n/*\n * bpf_setsockopt\n *\n * \tEmulate a call to **setsockopt()** on the socket associated to\n * \t*bpf_socket*, which must be a full socket. The *level* at\n * \twhich the option resides and the name *optname* of the option\n * \tmust be specified, see **setsockopt(2)** for more information.\n * \tThe option value of length *optlen* is pointed by *optval*.\n *\n * \t*bpf_socket* should be one of the following:\n *\n * \t* **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.\n * \t* **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**\n * \t  and **BPF_CGROUP_INET6_CONNECT**.\n *\n * \tThis helper actually implements a subset of **setsockopt()**.\n * \tIt supports the following *level*\\ s:\n *\n * \t* **SOL_SOCKET**, which supports the following *optname*\\ s:\n * \t  **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**,\n * \t  **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**,\n * \t  **SO_BINDTODEVICE**, **SO_KEEPALIVE**.\n * \t* **IPPROTO_TCP**, which supports the following *optname*\\ s:\n * \t  **TCP_CONGESTION**, **TCP_BPF_IW**,\n * \t  **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**,\n * \t  **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**,\n * \t  **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**.\n * \t* **IPPROTO_IP**, which supports *optname* **IP_TOS**.\n * \t* **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_setsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 49;\n\n/*\n * bpf_skb_adjust_room\n *\n * \tGrow or shrink the room for data in the packet associated to\n * \t*skb* by *len_diff*, and according to the selected *mode*.\n *\n * \tBy default, the helper will reset any offloaded checksum\n * \tindicator of the skb to CHECKSUM_NONE. This can be avoided\n * \tby the following flag:\n *\n * \t* **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded\n * \t  checksum data of the skb to CHECKSUM_NONE.\n *\n * \tThere are two supported modes at this time:\n *\n * \t* **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer\n * \t  (room space is added or removed below the layer 2 header).\n *\n * \t* **BPF_ADJ_ROOM_NET**: Adjust room at the network layer\n * \t  (room space is added or removed below the layer 3 header).\n *\n * \tThe following flags are supported at this time:\n *\n * \t* **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size.\n * \t  Adjusting mss in this way is not allowed for datagrams.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**,\n * \t  **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**:\n * \t  Any new space is reserved to hold a tunnel header.\n * \t  Configure skb offsets and other fields accordingly.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**,\n * \t  **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**:\n * \t  Use with ENCAP_L3 flags to further specify the tunnel type.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L2**\\ (*len*):\n * \t  Use with ENCAP_L3/L4 flags to further specify the tunnel\n * \t  type; *len* is the length of the inner MAC header.\n *\n * \t* **BPF_F_ADJ_ROOM_ENCAP_L2_ETH**:\n * \t  Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the\n * \t  L2 type as Ethernet.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_adjust_room)(struct __sk_buff *skb, __s32 len_diff, __u32 mode, __u64 flags) = (void *) 50;\n\n/*\n * bpf_redirect_map\n *\n * \tRedirect the packet to the endpoint referenced by *map* at\n * \tindex *key*. Depending on its type, this *map* can contain\n * \treferences to net devices (for forwarding packets through other\n * \tports), or to CPUs (for redirecting XDP frames to another CPU;\n * \tbut this is only implemented for native XDP (with driver\n * \tsupport) as of this writing).\n *\n * \tThe lower two bits of *flags* are used as the return code if\n * \tthe map lookup fails. This is so that the return value can be\n * \tone of the XDP program return codes up to **XDP_TX**, as chosen\n * \tby the caller. The higher bits of *flags* can be set to\n * \tBPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below.\n *\n * \tWith BPF_F_BROADCAST the packet will be broadcasted to all the\n * \tinterfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress\n * \tinterface will be excluded when do broadcasting.\n *\n * \tSee also **bpf_redirect**\\ (), which only supports redirecting\n * \tto an ifindex, but doesn't require a map to do so.\n *\n * Returns\n * \t**XDP_REDIRECT** on success, or the value of the two lower bits\n * \tof the *flags* argument on error.\n */\nstatic long (*bpf_redirect_map)(void *map, __u32 key, __u64 flags) = (void *) 51;\n\n/*\n * bpf_sk_redirect_map\n *\n * \tRedirect the packet to the socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_sk_redirect_map)(struct __sk_buff *skb, void *map, __u32 key, __u64 flags) = (void *) 52;\n\n/*\n * bpf_sock_map_update\n *\n * \tAdd an entry to, or update a *map* referencing sockets. The\n * \t*skops* is used as a new value for the entry associated to\n * \t*key*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tIf the *map* has eBPF programs (parser and verdict), those will\n * \tbe inherited by the socket being added. If the socket is\n * \talready attached to eBPF programs, this results in an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sock_map_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 53;\n\n/*\n * bpf_xdp_adjust_meta\n *\n * \tAdjust the address pointed by *xdp_md*\\ **->data_meta** by\n * \t*delta* (which can be positive or negative). Note that this\n * \toperation modifies the address stored in *xdp_md*\\ **->data**,\n * \tso the latter must be loaded only after the helper has been\n * \tcalled.\n *\n * \tThe use of *xdp_md*\\ **->data_meta** is optional and programs\n * \tare not required to use it. The rationale is that when the\n * \tpacket is processed with XDP (e.g. as DoS filter), it is\n * \tpossible to push further meta data along with it before passing\n * \tto the stack, and to give the guarantee that an ingress eBPF\n * \tprogram attached as a TC classifier on the same device can pick\n * \tthis up for further post-processing. Since TC works with socket\n * \tbuffers, it remains possible to set from XDP the **mark** or\n * \t**priority** pointers, or other pointers for the socket buffer.\n * \tHaving this scratch space generic and programmable allows for\n * \tmore flexibility as the user is free to store whatever meta\n * \tdata they need.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_meta)(struct xdp_md *xdp_md, int delta) = (void *) 54;\n\n/*\n * bpf_perf_event_read_value\n *\n * \tRead the value of a perf event counter, and store it into *buf*\n * \tof size *buf_size*. This helper relies on a *map* of type\n * \t**BPF_MAP_TYPE_PERF_EVENT_ARRAY**. The nature of the perf event\n * \tcounter is selected when *map* is updated with perf event file\n * \tdescriptors. The *map* is an array whose size is the number of\n * \tavailable CPUs, and each cell contains a value relative to one\n * \tCPU. The value to retrieve is indicated by *flags*, that\n * \tcontains the index of the CPU to look up, masked with\n * \t**BPF_F_INDEX_MASK**. Alternatively, *flags* can be set to\n * \t**BPF_F_CURRENT_CPU** to indicate that the value for the\n * \tcurrent CPU should be retrieved.\n *\n * \tThis helper behaves in a way close to\n * \t**bpf_perf_event_read**\\ () helper, save that instead of\n * \tjust returning the value observed, it fills the *buf*\n * \tstructure. This allows for additional data to be retrieved: in\n * \tparticular, the enabled and running times (in *buf*\\\n * \t**->enabled** and *buf*\\ **->running**, respectively) are\n * \tcopied. In general, **bpf_perf_event_read_value**\\ () is\n * \trecommended over **bpf_perf_event_read**\\ (), which has some\n * \tABI issues and provides fewer functionalities.\n *\n * \tThese values are interesting, because hardware PMU (Performance\n * \tMonitoring Unit) counters are limited resources. When there are\n * \tmore PMU based perf events opened than available counters,\n * \tkernel will multiplex these events so each event gets certain\n * \tpercentage (but not all) of the PMU time. In case that\n * \tmultiplexing happens, the number of samples or counter value\n * \twill not reflect the case compared to when no multiplexing\n * \toccurs. This makes comparison between different runs difficult.\n * \tTypically, the counter value should be normalized before\n * \tcomparing to other experiments. The usual normalization is done\n * \tas follows.\n *\n * \t::\n *\n * \t\tnormalized_counter = counter * t_enabled / t_running\n *\n * \tWhere t_enabled is the time enabled for event and t_running is\n * \tthe time running for event since last normalization. The\n * \tenabled and running times are accumulated since the perf event\n * \topen. To achieve scaling factor between two invocations of an\n * \teBPF program, users can use CPU id as the key (which is\n * \ttypical for perf array usage model) to remember the previous\n * \tvalue and do the calculation inside the eBPF program.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_event_read_value)(void *map, __u64 flags, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 55;\n\n/*\n * bpf_perf_prog_read_value\n *\n * \tFor en eBPF program attached to a perf event, retrieve the\n * \tvalue of the event counter associated to *ctx* and store it in\n * \tthe structure pointed by *buf* and of size *buf_size*. Enabled\n * \tand running times are also stored in the structure (see\n * \tdescription of helper **bpf_perf_event_read_value**\\ () for\n * \tmore details).\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_perf_prog_read_value)(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, __u32 buf_size) = (void *) 56;\n\n/*\n * bpf_getsockopt\n *\n * \tEmulate a call to **getsockopt()** on the socket associated to\n * \t*bpf_socket*, which must be a full socket. The *level* at\n * \twhich the option resides and the name *optname* of the option\n * \tmust be specified, see **getsockopt(2)** for more information.\n * \tThe retrieved value is stored in the structure pointed by\n * \t*opval* and of length *optlen*.\n *\n * \t*bpf_socket* should be one of the following:\n *\n * \t* **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**.\n * \t* **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT**\n * \t  and **BPF_CGROUP_INET6_CONNECT**.\n *\n * \tThis helper actually implements a subset of **getsockopt()**.\n * \tIt supports the following *level*\\ s:\n *\n * \t* **IPPROTO_TCP**, which supports *optname*\n * \t  **TCP_CONGESTION**.\n * \t* **IPPROTO_IP**, which supports *optname* **IP_TOS**.\n * \t* **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_getsockopt)(void *bpf_socket, int level, int optname, void *optval, int optlen) = (void *) 57;\n\n/*\n * bpf_override_return\n *\n * \tUsed for error injection, this helper uses kprobes to override\n * \tthe return value of the probed function, and to set it to *rc*.\n * \tThe first argument is the context *regs* on which the kprobe\n * \tworks.\n *\n * \tThis helper works by setting the PC (program counter)\n * \tto an override function which is run in place of the original\n * \tprobed function. This means the probed function is not run at\n * \tall. The replacement function just returns with the required\n * \tvalue.\n *\n * \tThis helper has security implications, and thus is subject to\n * \trestrictions. It is only available if the kernel was compiled\n * \twith the **CONFIG_BPF_KPROBE_OVERRIDE** configuration\n * \toption, and in this case it only works on functions tagged with\n * \t**ALLOW_ERROR_INJECTION** in the kernel code.\n *\n * \tAlso, the helper is only available for the architectures having\n * \tthe CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing,\n * \tx86 architecture is the only one to support this feature.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_override_return)(struct pt_regs *regs, __u64 rc) = (void *) 58;\n\n/*\n * bpf_sock_ops_cb_flags_set\n *\n * \tAttempt to set the value of the **bpf_sock_ops_cb_flags** field\n * \tfor the full TCP socket associated to *bpf_sock_ops* to\n * \t*argval*.\n *\n * \tThe primary use of this field is to determine if there should\n * \tbe calls to eBPF programs of type\n * \t**BPF_PROG_TYPE_SOCK_OPS** at various points in the TCP\n * \tcode. A program of the same type can change its value, per\n * \tconnection and as necessary, when the connection is\n * \testablished. This field is directly accessible for reading, but\n * \tthis helper must be used for updates in order to return an\n * \terror if an eBPF program tries to set a callback that is not\n * \tsupported in the current kernel.\n *\n * \t*argval* is a flag array which can combine these flags:\n *\n * \t* **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out)\n * \t* **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission)\n * \t* **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change)\n * \t* **BPF_SOCK_OPS_RTT_CB_FLAG** (every RTT)\n *\n * \tTherefore, this function can be used to clear a callback flag by\n * \tsetting the appropriate bit to zero. e.g. to disable the RTO\n * \tcallback:\n *\n * \t**bpf_sock_ops_cb_flags_set(bpf_sock,**\n * \t\t**bpf_sock->bpf_sock_ops_cb_flags & ~BPF_SOCK_OPS_RTO_CB_FLAG)**\n *\n * \tHere are some examples of where one could call such eBPF\n * \tprogram:\n *\n * \t* When RTO fires.\n * \t* When a packet is retransmitted.\n * \t* When the connection terminates.\n * \t* When a packet is sent.\n * \t* When a packet is received.\n *\n * Returns\n * \tCode **-EINVAL** if the socket is not a full TCP socket;\n * \totherwise, a positive number containing the bits that could not\n * \tbe set is returned (which comes down to 0 if all bits were set\n * \tas required).\n */\nstatic long (*bpf_sock_ops_cb_flags_set)(struct bpf_sock_ops *bpf_sock, int argval) = (void *) 59;\n\n/*\n * bpf_msg_redirect_map\n *\n * \tThis helper is used in programs implementing policies at the\n * \tsocket level. If the message *msg* is allowed to pass (i.e. if\n * \tthe verdict eBPF program returns **SK_PASS**), redirect it to\n * \tthe socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_msg_redirect_map)(struct sk_msg_md *msg, void *map, __u32 key, __u64 flags) = (void *) 60;\n\n/*\n * bpf_msg_apply_bytes\n *\n * \tFor socket policies, apply the verdict of the eBPF program to\n * \tthe next *bytes* (number of bytes) of message *msg*.\n *\n * \tFor example, this helper can be used in the following cases:\n *\n * \t* A single **sendmsg**\\ () or **sendfile**\\ () system call\n * \t  contains multiple logical messages that the eBPF program is\n * \t  supposed to read and for which it should apply a verdict.\n * \t* An eBPF program only cares to read the first *bytes* of a\n * \t  *msg*. If the message has a large payload, then setting up\n * \t  and calling the eBPF program repeatedly for all bytes, even\n * \t  though the verdict is already known, would create unnecessary\n * \t  overhead.\n *\n * \tWhen called from within an eBPF program, the helper sets a\n * \tcounter internal to the BPF infrastructure, that is used to\n * \tapply the last verdict to the next *bytes*. If *bytes* is\n * \tsmaller than the current data being processed from a\n * \t**sendmsg**\\ () or **sendfile**\\ () system call, the first\n * \t*bytes* will be sent and the eBPF program will be re-run with\n * \tthe pointer for start of data pointing to byte number *bytes*\n * \t**+ 1**. If *bytes* is larger than the current data being\n * \tprocessed, then the eBPF verdict will be applied to multiple\n * \t**sendmsg**\\ () or **sendfile**\\ () calls until *bytes* are\n * \tconsumed.\n *\n * \tNote that if a socket closes with the internal counter holding\n * \ta non-zero value, this is not a problem because data is not\n * \tbeing buffered for *bytes* and is sent as it is received.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_msg_apply_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 61;\n\n/*\n * bpf_msg_cork_bytes\n *\n * \tFor socket policies, prevent the execution of the verdict eBPF\n * \tprogram for message *msg* until *bytes* (byte number) have been\n * \taccumulated.\n *\n * \tThis can be used when one needs a specific number of bytes\n * \tbefore a verdict can be assigned, even if the data spans\n * \tmultiple **sendmsg**\\ () or **sendfile**\\ () calls. The extreme\n * \tcase would be a user calling **sendmsg**\\ () repeatedly with\n * \t1-byte long message segments. Obviously, this is bad for\n * \tperformance, but it is still valid. If the eBPF program needs\n * \t*bytes* bytes to validate a header, this helper can be used to\n * \tprevent the eBPF program to be called again until *bytes* have\n * \tbeen accumulated.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_msg_cork_bytes)(struct sk_msg_md *msg, __u32 bytes) = (void *) 62;\n\n/*\n * bpf_msg_pull_data\n *\n * \tFor socket policies, pull in non-linear data from user space\n * \tfor *msg* and set pointers *msg*\\ **->data** and *msg*\\\n * \t**->data_end** to *start* and *end* bytes offsets into *msg*,\n * \trespectively.\n *\n * \tIf a program of type **BPF_PROG_TYPE_SK_MSG** is run on a\n * \t*msg* it can only parse data that the (**data**, **data_end**)\n * \tpointers have already consumed. For **sendmsg**\\ () hooks this\n * \tis likely the first scatterlist element. But for calls relying\n * \ton the **sendpage** handler (e.g. **sendfile**\\ ()) this will\n * \tbe the range (**0**, **0**) because the data is shared with\n * \tuser space and by default the objective is to avoid allowing\n * \tuser space to modify data while (or after) eBPF verdict is\n * \tbeing decided. This helper can be used to pull in data and to\n * \tset the start and end pointer to given values. Data will be\n * \tcopied if necessary (i.e. if data was not linear and if start\n * \tand end pointers do not point to the same chunk).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_pull_data)(struct sk_msg_md *msg, __u32 start, __u32 end, __u64 flags) = (void *) 63;\n\n/*\n * bpf_bind\n *\n * \tBind the socket associated to *ctx* to the address pointed by\n * \t*addr*, of length *addr_len*. This allows for making outgoing\n * \tconnection from the desired IP address, which can be useful for\n * \texample when all processes inside a cgroup should use one\n * \tsingle IP address on a host that has multiple IP configured.\n *\n * \tThis helper works for IPv4 and IPv6, TCP and UDP sockets. The\n * \tdomain (*addr*\\ **->sa_family**) must be **AF_INET** (or\n * \t**AF_INET6**). It's advised to pass zero port (**sin_port**\n * \tor **sin6_port**) which triggers IP_BIND_ADDRESS_NO_PORT-like\n * \tbehavior and lets the kernel efficiently pick up an unused\n * \tport as long as 4-tuple is unique. Passing non-zero port might\n * \tlead to degraded performance.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_bind)(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len) = (void *) 64;\n\n/*\n * bpf_xdp_adjust_tail\n *\n * \tAdjust (move) *xdp_md*\\ **->data_end** by *delta* bytes. It is\n * \tpossible to both shrink and grow the packet tail.\n * \tShrink done via *delta* being a negative integer.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *) 65;\n\n/*\n * bpf_skb_get_xfrm_state\n *\n * \tRetrieve the XFRM state (IP transform framework, see also\n * \t**ip-xfrm(8)**) at *index* in XFRM \"security path\" for *skb*.\n *\n * \tThe retrieved value is stored in the **struct bpf_xfrm_state**\n * \tpointed by *xfrm_state* and of length *size*.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_XFRM** configuration option.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_get_xfrm_state)(struct __sk_buff *skb, __u32 index, struct bpf_xfrm_state *xfrm_state, __u32 size, __u64 flags) = (void *) 66;\n\n/*\n * bpf_get_stack\n *\n * \tReturn a user or a kernel stack in bpf program provided buffer.\n * \tTo achieve this, the helper needs *ctx*, which is a pointer\n * \tto the context on which the tracing program is executed.\n * \tTo store the stacktrace, the bpf program provides *buf* with\n * \ta nonnegative *size*.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \tthe following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_USER_BUILD_ID**\n * \t\tCollect buildid+offset instead of ips for user stack,\n * \t\tonly valid if **BPF_F_USER_STACK** is also specified.\n *\n * \t**bpf_get_stack**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames, subject\n * \tto sufficient large buffer size. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tA non-negative value equal to or less than *size* on success,\n * \tor a negative error in case of failure.\n */\nstatic long (*bpf_get_stack)(void *ctx, void *buf, __u32 size, __u64 flags) = (void *) 67;\n\n/*\n * bpf_skb_load_bytes_relative\n *\n * \tThis helper is similar to **bpf_skb_load_bytes**\\ () in that\n * \tit provides an easy way to load *len* bytes from *offset*\n * \tfrom the packet associated to *skb*, into the buffer pointed\n * \tby *to*. The difference to **bpf_skb_load_bytes**\\ () is that\n * \ta fifth argument *start_header* exists in order to select a\n * \tbase offset to start from. *start_header* can be one of:\n *\n * \t**BPF_HDR_START_MAC**\n * \t\tBase offset to load data from is *skb*'s mac header.\n * \t**BPF_HDR_START_NET**\n * \t\tBase offset to load data from is *skb*'s network header.\n *\n * \tIn general, \"direct packet access\" is the preferred method to\n * \taccess packet data, however, this helper is in particular useful\n * \tin socket filters where *skb*\\ **->data** does not always point\n * \tto the start of the mac header and where \"direct packet access\"\n * \tis not available.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_load_bytes_relative)(const void *skb, __u32 offset, void *to, __u32 len, __u32 start_header) = (void *) 68;\n\n/*\n * bpf_fib_lookup\n *\n * \tDo FIB lookup in kernel tables using parameters in *params*.\n * \tIf lookup is successful and result shows packet is to be\n * \tforwarded, the neighbor tables are searched for the nexthop.\n * \tIf successful (ie., FIB lookup shows forwarding and nexthop\n * \tis resolved), the nexthop address is returned in ipv4_dst\n * \tor ipv6_dst based on family, smac is set to mac address of\n * \tegress device, dmac is set to nexthop mac address, rt_metric\n * \tis set to metric from route (IPv4/IPv6 only), and ifindex\n * \tis set to the device index of the nexthop from the FIB lookup.\n *\n * \t*plen* argument is the size of the passed in struct.\n * \t*flags* argument can be a combination of one or more of the\n * \tfollowing values:\n *\n * \t**BPF_FIB_LOOKUP_DIRECT**\n * \t\tDo a direct table lookup vs full lookup using FIB\n * \t\trules.\n * \t**BPF_FIB_LOOKUP_OUTPUT**\n * \t\tPerform lookup from an egress perspective (default is\n * \t\tingress).\n *\n * \t*ctx* is either **struct xdp_md** for XDP programs or\n * \t**struct sk_buff** tc cls_act programs.\n *\n * Returns\n * \t* < 0 if any input argument is invalid\n * \t*   0 on success (packet is forwarded, nexthop neighbor exists)\n * \t* > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the\n * \t  packet is not forwarded or needs assist from full stack\n *\n * \tIf lookup fails with BPF_FIB_LKUP_RET_FRAG_NEEDED, then the MTU\n * \twas exceeded and output params->mtu_result contains the MTU.\n */\nstatic long (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, int plen, __u32 flags) = (void *) 69;\n\n/*\n * bpf_sock_hash_update\n *\n * \tAdd an entry to, or update a sockhash *map* referencing sockets.\n * \tThe *skops* is used as a new value for the entry associated to\n * \t*key*. *flags* is one of:\n *\n * \t**BPF_NOEXIST**\n * \t\tThe entry for *key* must not exist in the map.\n * \t**BPF_EXIST**\n * \t\tThe entry for *key* must already exist in the map.\n * \t**BPF_ANY**\n * \t\tNo condition on the existence of the entry for *key*.\n *\n * \tIf the *map* has eBPF programs (parser and verdict), those will\n * \tbe inherited by the socket being added. If the socket is\n * \talready attached to eBPF programs, this results in an error.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sock_hash_update)(struct bpf_sock_ops *skops, void *map, void *key, __u64 flags) = (void *) 70;\n\n/*\n * bpf_msg_redirect_hash\n *\n * \tThis helper is used in programs implementing policies at the\n * \tsocket level. If the message *msg* is allowed to pass (i.e. if\n * \tthe verdict eBPF program returns **SK_PASS**), redirect it to\n * \tthe socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress path otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_msg_redirect_hash)(struct sk_msg_md *msg, void *map, void *key, __u64 flags) = (void *) 71;\n\n/*\n * bpf_sk_redirect_hash\n *\n * \tThis helper is used in programs implementing policies at the\n * \tskb socket level. If the sk_buff *skb* is allowed to pass (i.e.\n * \tif the verdict eBPF program returns **SK_PASS**), redirect it\n * \tto the socket referenced by *map* (of type\n * \t**BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and\n * \tegress interfaces can be used for redirection. The\n * \t**BPF_F_INGRESS** value in *flags* is used to make the\n * \tdistinction (ingress path is selected if the flag is present,\n * \tegress otherwise). This is the only flag supported for now.\n *\n * Returns\n * \t**SK_PASS** on success, or **SK_DROP** on error.\n */\nstatic long (*bpf_sk_redirect_hash)(struct __sk_buff *skb, void *map, void *key, __u64 flags) = (void *) 72;\n\n/*\n * bpf_lwt_push_encap\n *\n * \tEncapsulate the packet associated to *skb* within a Layer 3\n * \tprotocol header. This header is provided in the buffer at\n * \taddress *hdr*, with *len* its size in bytes. *type* indicates\n * \tthe protocol of the header and can be one of:\n *\n * \t**BPF_LWT_ENCAP_SEG6**\n * \t\tIPv6 encapsulation with Segment Routing Header\n * \t\t(**struct ipv6_sr_hdr**). *hdr* only contains the SRH,\n * \t\tthe IPv6 header is computed by the kernel.\n * \t**BPF_LWT_ENCAP_SEG6_INLINE**\n * \t\tOnly works if *skb* contains an IPv6 packet. Insert a\n * \t\tSegment Routing Header (**struct ipv6_sr_hdr**) inside\n * \t\tthe IPv6 header.\n * \t**BPF_LWT_ENCAP_IP**\n * \t\tIP encapsulation (GRE/GUE/IPIP/etc). The outer header\n * \t\tmust be IPv4 or IPv6, followed by zero or more\n * \t\tadditional headers, up to **LWT_BPF_MAX_HEADROOM**\n * \t\ttotal bytes in all prepended headers. Please note that\n * \t\tif **skb_is_gso**\\ (*skb*) is true, no more than two\n * \t\theaders can be prepended, and the inner header, if\n * \t\tpresent, should be either GRE or UDP/GUE.\n *\n * \t**BPF_LWT_ENCAP_SEG6**\\ \\* types can be called by BPF programs\n * \tof type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can\n * \tbe called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and\n * \t**BPF_PROG_TYPE_LWT_XMIT**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_push_encap)(struct __sk_buff *skb, __u32 type, void *hdr, __u32 len) = (void *) 73;\n\n/*\n * bpf_lwt_seg6_store_bytes\n *\n * \tStore *len* bytes from address *from* into the packet\n * \tassociated to *skb*, at *offset*. Only the flags, tag and TLVs\n * \tinside the outermost IPv6 Segment Routing Header can be\n * \tmodified through this helper.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_store_bytes)(struct __sk_buff *skb, __u32 offset, const void *from, __u32 len) = (void *) 74;\n\n/*\n * bpf_lwt_seg6_adjust_srh\n *\n * \tAdjust the size allocated to TLVs in the outermost IPv6\n * \tSegment Routing Header contained in the packet associated to\n * \t*skb*, at position *offset* by *delta* bytes. Only offsets\n * \tafter the segments are accepted. *delta* can be as well\n * \tpositive (growing) as negative (shrinking).\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_adjust_srh)(struct __sk_buff *skb, __u32 offset, __s32 delta) = (void *) 75;\n\n/*\n * bpf_lwt_seg6_action\n *\n * \tApply an IPv6 Segment Routing action of type *action* to the\n * \tpacket associated to *skb*. Each action takes a parameter\n * \tcontained at address *param*, and of length *param_len* bytes.\n * \t*action* can be one of:\n *\n * \t**SEG6_LOCAL_ACTION_END_X**\n * \t\tEnd.X action: Endpoint with Layer-3 cross-connect.\n * \t\tType of *param*: **struct in6_addr**.\n * \t**SEG6_LOCAL_ACTION_END_T**\n * \t\tEnd.T action: Endpoint with specific IPv6 table lookup.\n * \t\tType of *param*: **int**.\n * \t**SEG6_LOCAL_ACTION_END_B6**\n * \t\tEnd.B6 action: Endpoint bound to an SRv6 policy.\n * \t\tType of *param*: **struct ipv6_sr_hdr**.\n * \t**SEG6_LOCAL_ACTION_END_B6_ENCAP**\n * \t\tEnd.B6.Encap action: Endpoint bound to an SRv6\n * \t\tencapsulation policy.\n * \t\tType of *param*: **struct ipv6_sr_hdr**.\n *\n * \tA call to this helper is susceptible to change the underlying\n * \tpacket buffer. Therefore, at load time, all checks on pointers\n * \tpreviously done by the verifier are invalidated and must be\n * \tperformed again, if the helper is used in combination with\n * \tdirect packet access.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_lwt_seg6_action)(struct __sk_buff *skb, __u32 action, void *param, __u32 param_len) = (void *) 76;\n\n/*\n * bpf_rc_repeat\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded repeat key message. This delays\n * \tthe generation of a key up event for previously generated\n * \tkey down event.\n *\n * \tSome IR protocols like NEC have a special IR message for\n * \trepeating last button, for when a button is held down.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_repeat)(void *ctx) = (void *) 77;\n\n/*\n * bpf_rc_keydown\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded key press with *scancode*,\n * \t*toggle* value in the given *protocol*. The scancode will be\n * \ttranslated to a keycode using the rc keymap, and reported as\n * \tan input key down event. After a period a key up event is\n * \tgenerated. This period can be extended by calling either\n * \t**bpf_rc_keydown**\\ () again with the same values, or calling\n * \t**bpf_rc_repeat**\\ ().\n *\n * \tSome protocols include a toggle bit, in case the button was\n * \treleased and pressed again between consecutive scancodes.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThe *protocol* is the decoded protocol number (see\n * \t**enum rc_proto** for some predefined values).\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_keydown)(void *ctx, __u32 protocol, __u64 scancode, __u32 toggle) = (void *) 78;\n\n/*\n * bpf_skb_cgroup_id\n *\n * \tReturn the cgroup v2 id of the socket associated with the *skb*.\n * \tThis is roughly similar to the **bpf_get_cgroup_classid**\\ ()\n * \thelper for cgroup v1 by providing a tag resp. identifier that\n * \tcan be matched on or used for map lookups e.g. to implement\n * \tpolicy. The cgroup v2 id of a given path in the hierarchy is\n * \texposed in user space through the f_handle API in order to get\n * \tto the same 64-bit id.\n *\n * \tThis helper can be used on TC egress path, but not on ingress,\n * \tand is available only if the kernel was compiled with the\n * \t**CONFIG_SOCK_CGROUP_DATA** configuration option.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_cgroup_id)(struct __sk_buff *skb) = (void *) 79;\n\n/*\n * bpf_get_current_cgroup_id\n *\n *\n * Returns\n * \tA 64-bit integer containing the current cgroup id based\n * \ton the cgroup within which the current task is running.\n */\nstatic __u64 (*bpf_get_current_cgroup_id)(void) = (void *) 80;\n\n/*\n * bpf_get_local_storage\n *\n * \tGet the pointer to the local storage area.\n * \tThe type and the size of the local storage is defined\n * \tby the *map* argument.\n * \tThe *flags* meaning is specific for each map type,\n * \tand has to be 0 for cgroup local storage.\n *\n * \tDepending on the BPF program type, a local storage area\n * \tcan be shared between multiple instances of the BPF program,\n * \trunning simultaneously.\n *\n * \tA user should care about the synchronization by himself.\n * \tFor example, by using the **BPF_ATOMIC** instructions to alter\n * \tthe shared data.\n *\n * Returns\n * \tA pointer to the local storage area.\n */\nstatic void *(*bpf_get_local_storage)(void *map, __u64 flags) = (void *) 81;\n\n/*\n * bpf_sk_select_reuseport\n *\n * \tSelect a **SO_REUSEPORT** socket from a\n * \t**BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*.\n * \tIt checks the selected socket is matching the incoming\n * \trequest in the socket buffer.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sk_select_reuseport)(struct sk_reuseport_md *reuse, void *map, void *key, __u64 flags) = (void *) 82;\n\n/*\n * bpf_skb_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of cgroup associated\n * \twith the *skb* at the *ancestor_level*.  The root cgroup is at\n * \t*ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with *skb*, then return value will be same as that\n * \tof **bpf_skb_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith *skb*.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_skb_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_ancestor_cgroup_id)(struct __sk_buff *skb, int ancestor_level) = (void *) 83;\n\n/*\n * bpf_sk_lookup_tcp\n *\n * \tLook for TCP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThe *ctx* should point to the context of the program, such as\n * \tthe skb or socket (depending on the hook in use). This is used\n * \tto determine the base network namespace for the lookup.\n *\n * \t*tuple_size* must be one of:\n *\n * \t**sizeof**\\ (*tuple*\\ **->ipv4**)\n * \t\tLook for an IPv4 socket.\n * \t**sizeof**\\ (*tuple*\\ **->ipv6**)\n * \t\tLook for an IPv6 socket.\n *\n * \tIf the *netns* is a negative signed 32-bit integer, then the\n * \tsocket lookup table in the netns associated with the *ctx*\n * \twill be used. For the TC hooks, this is the netns of the device\n * \tin the skb. For socket hooks, this is the netns of the socket.\n * \tIf *netns* is any other signed 32-bit value greater than or\n * \tequal to zero then it specifies the ID of the netns relative to\n * \tthe netns associated with the *ctx*. *netns* values beyond the\n * \trange of 32-bit integers are reserved for future use.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 84;\n\n/*\n * bpf_sk_lookup_udp\n *\n * \tLook for UDP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThe *ctx* should point to the context of the program, such as\n * \tthe skb or socket (depending on the hook in use). This is used\n * \tto determine the base network namespace for the lookup.\n *\n * \t*tuple_size* must be one of:\n *\n * \t**sizeof**\\ (*tuple*\\ **->ipv4**)\n * \t\tLook for an IPv4 socket.\n * \t**sizeof**\\ (*tuple*\\ **->ipv6**)\n * \t\tLook for an IPv6 socket.\n *\n * \tIf the *netns* is a negative signed 32-bit integer, then the\n * \tsocket lookup table in the netns associated with the *ctx*\n * \twill be used. For the TC hooks, this is the netns of the device\n * \tin the skb. For socket hooks, this is the netns of the socket.\n * \tIf *netns* is any other signed 32-bit value greater than or\n * \tequal to zero then it specifies the ID of the netns relative to\n * \tthe netns associated with the *ctx*. *netns* values beyond the\n * \trange of 32-bit integers are reserved for future use.\n *\n * \tAll values for *flags* are reserved for future usage, and must\n * \tbe left at zero.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 85;\n\n/*\n * bpf_sk_release\n *\n * \tRelease the reference held by *sock*. *sock* must be a\n * \tnon-**NULL** pointer that was returned from\n * \t**bpf_sk_lookup_xxx**\\ ().\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_sk_release)(void *sock) = (void *) 86;\n\n/*\n * bpf_map_push_elem\n *\n * \tPush an element *value* in *map*. *flags* is one of:\n *\n * \t**BPF_EXIST**\n * \t\tIf the queue/stack is full, the oldest element is\n * \t\tremoved to make room for this.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_push_elem)(void *map, const void *value, __u64 flags) = (void *) 87;\n\n/*\n * bpf_map_pop_elem\n *\n * \tPop an element from *map*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_pop_elem)(void *map, void *value) = (void *) 88;\n\n/*\n * bpf_map_peek_elem\n *\n * \tGet an element from *map* without removing it.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_map_peek_elem)(void *map, void *value) = (void *) 89;\n\n/*\n * bpf_msg_push_data\n *\n * \tFor socket policies, insert *len* bytes into *msg* at offset\n * \t*start*.\n *\n * \tIf a program of type **BPF_PROG_TYPE_SK_MSG** is run on a\n * \t*msg* it may want to insert metadata or options into the *msg*.\n * \tThis can later be read and used by any of the lower layer BPF\n * \thooks.\n *\n * \tThis helper may fail if under memory pressure (a malloc\n * \tfails) in these cases BPF programs will get an appropriate\n * \terror and BPF programs will need to handle them.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_push_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 90;\n\n/*\n * bpf_msg_pop_data\n *\n * \tWill remove *len* bytes from a *msg* starting at byte *start*.\n * \tThis may result in **ENOMEM** errors under certain situations if\n * \tan allocation and copy are required due to a full ring buffer.\n * \tHowever, the helper will try to avoid doing the allocation\n * \tif possible. Other errors can occur if input parameters are\n * \tinvalid either due to *start* byte not being valid part of *msg*\n * \tpayload and/or *pop* value being to large.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_msg_pop_data)(struct sk_msg_md *msg, __u32 start, __u32 len, __u64 flags) = (void *) 91;\n\n/*\n * bpf_rc_pointer_rel\n *\n * \tThis helper is used in programs implementing IR decoding, to\n * \treport a successfully decoded pointer movement.\n *\n * \tThe *ctx* should point to the lirc sample as passed into\n * \tthe program.\n *\n * \tThis helper is only available is the kernel was compiled with\n * \tthe **CONFIG_BPF_LIRC_MODE2** configuration option set to\n * \t\"**y**\".\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_rc_pointer_rel)(void *ctx, __s32 rel_x, __s32 rel_y) = (void *) 92;\n\n/*\n * bpf_spin_lock\n *\n * \tAcquire a spinlock represented by the pointer *lock*, which is\n * \tstored as part of a value of a map. Taking the lock allows to\n * \tsafely update the rest of the fields in that value. The\n * \tspinlock can (and must) later be released with a call to\n * \t**bpf_spin_unlock**\\ (\\ *lock*\\ ).\n *\n * \tSpinlocks in BPF programs come with a number of restrictions\n * \tand constraints:\n *\n * \t* **bpf_spin_lock** objects are only allowed inside maps of\n * \t  types **BPF_MAP_TYPE_HASH** and **BPF_MAP_TYPE_ARRAY** (this\n * \t  list could be extended in the future).\n * \t* BTF description of the map is mandatory.\n * \t* The BPF program can take ONE lock at a time, since taking two\n * \t  or more could cause dead locks.\n * \t* Only one **struct bpf_spin_lock** is allowed per map element.\n * \t* When the lock is taken, calls (either BPF to BPF or helpers)\n * \t  are not allowed.\n * \t* The **BPF_LD_ABS** and **BPF_LD_IND** instructions are not\n * \t  allowed inside a spinlock-ed region.\n * \t* The BPF program MUST call **bpf_spin_unlock**\\ () to release\n * \t  the lock, on all execution paths, before it returns.\n * \t* The BPF program can access **struct bpf_spin_lock** only via\n * \t  the **bpf_spin_lock**\\ () and **bpf_spin_unlock**\\ ()\n * \t  helpers. Loading or storing data into the **struct\n * \t  bpf_spin_lock** *lock*\\ **;** field of a map is not allowed.\n * \t* To use the **bpf_spin_lock**\\ () helper, the BTF description\n * \t  of the map value must be a struct and have **struct\n * \t  bpf_spin_lock** *anyname*\\ **;** field at the top level.\n * \t  Nested lock inside another struct is not allowed.\n * \t* The **struct bpf_spin_lock** *lock* field in a map value must\n * \t  be aligned on a multiple of 4 bytes in that value.\n * \t* Syscall with command **BPF_MAP_LOOKUP_ELEM** does not copy\n * \t  the **bpf_spin_lock** field to user space.\n * \t* Syscall with command **BPF_MAP_UPDATE_ELEM**, or update from\n * \t  a BPF program, do not update the **bpf_spin_lock** field.\n * \t* **bpf_spin_lock** cannot be on the stack or inside a\n * \t  networking packet (it can only be inside of a map values).\n * \t* **bpf_spin_lock** is available to root only.\n * \t* Tracing programs and socket filter programs cannot use\n * \t  **bpf_spin_lock**\\ () due to insufficient preemption checks\n * \t  (but this may change in the future).\n * \t* **bpf_spin_lock** is not allowed in inner maps of map-in-map.\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_spin_lock)(struct bpf_spin_lock *lock) = (void *) 93;\n\n/*\n * bpf_spin_unlock\n *\n * \tRelease the *lock* previously locked by a call to\n * \t**bpf_spin_lock**\\ (\\ *lock*\\ ).\n *\n * Returns\n * \t0\n */\nstatic long (*bpf_spin_unlock)(struct bpf_spin_lock *lock) = (void *) 94;\n\n/*\n * bpf_sk_fullsock\n *\n * \tThis helper gets a **struct bpf_sock** pointer such\n * \tthat all the fields in this **bpf_sock** can be accessed.\n *\n * Returns\n * \tA **struct bpf_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_sock *(*bpf_sk_fullsock)(struct bpf_sock *sk) = (void *) 95;\n\n/*\n * bpf_tcp_sock\n *\n * \tThis helper gets a **struct bpf_tcp_sock** pointer from a\n * \t**struct bpf_sock** pointer.\n *\n * Returns\n * \tA **struct bpf_tcp_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_tcp_sock *(*bpf_tcp_sock)(struct bpf_sock *sk) = (void *) 96;\n\n/*\n * bpf_skb_ecn_set_ce\n *\n * \tSet ECN (Explicit Congestion Notification) field of IP header\n * \tto **CE** (Congestion Encountered) if current value is **ECT**\n * \t(ECN Capable Transport). Otherwise, do nothing. Works with IPv6\n * \tand IPv4.\n *\n * Returns\n * \t1 if the **CE** flag is set (either by the current helper call\n * \tor because it was already present), 0 if it is not set.\n */\nstatic long (*bpf_skb_ecn_set_ce)(struct __sk_buff *skb) = (void *) 97;\n\n/*\n * bpf_get_listener_sock\n *\n * \tReturn a **struct bpf_sock** pointer in **TCP_LISTEN** state.\n * \t**bpf_sk_release**\\ () is unnecessary and not allowed.\n *\n * Returns\n * \tA **struct bpf_sock** pointer on success, or **NULL** in\n * \tcase of failure.\n */\nstatic struct bpf_sock *(*bpf_get_listener_sock)(struct bpf_sock *sk) = (void *) 98;\n\n/*\n * bpf_skc_lookup_tcp\n *\n * \tLook for TCP socket matching *tuple*, optionally in a child\n * \tnetwork namespace *netns*. The return value must be checked,\n * \tand if non-**NULL**, released via **bpf_sk_release**\\ ().\n *\n * \tThis function is identical to **bpf_sk_lookup_tcp**\\ (), except\n * \tthat it also returns timewait or request sockets. Use\n * \t**bpf_sk_fullsock**\\ () or **bpf_tcp_sock**\\ () to access the\n * \tfull structure.\n *\n * \tThis helper is available only if the kernel was compiled with\n * \t**CONFIG_NET** configuration option.\n *\n * Returns\n * \tPointer to **struct bpf_sock**, or **NULL** in case of failure.\n * \tFor sockets with reuseport option, the **struct bpf_sock**\n * \tresult is from *reuse*\\ **->socks**\\ [] using the hash of the\n * \ttuple.\n */\nstatic struct bpf_sock *(*bpf_skc_lookup_tcp)(void *ctx, struct bpf_sock_tuple *tuple, __u32 tuple_size, __u64 netns, __u64 flags) = (void *) 99;\n\n/*\n * bpf_tcp_check_syncookie\n *\n * \tCheck whether *iph* and *th* contain a valid SYN cookie ACK for\n * \tthe listening socket in *sk*.\n *\n * \t*iph* points to the start of the IPv4 or IPv6 header, while\n * \t*iph_len* contains **sizeof**\\ (**struct iphdr**) or\n * \t**sizeof**\\ (**struct ip6hdr**).\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains **sizeof**\\ (**struct tcphdr**).\n *\n * Returns\n * \t0 if *iph* and *th* are a valid SYN cookie ACK, or a negative\n * \terror otherwise.\n */\nstatic long (*bpf_tcp_check_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 100;\n\n/*\n * bpf_sysctl_get_name\n *\n * \tGet name of sysctl in /proc/sys/ and copy it into provided by\n * \tprogram buffer *buf* of size *buf_len*.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * \tIf *flags* is zero, full name (e.g. \"net/ipv4/tcp_mem\") is\n * \tcopied. Use **BPF_F_SYSCTL_BASE_NAME** flag to copy base name\n * \tonly (e.g. \"tcp_mem\").\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n */\nstatic long (*bpf_sysctl_get_name)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len, __u64 flags) = (void *) 101;\n\n/*\n * bpf_sysctl_get_current_value\n *\n * \tGet current value of sysctl as it is presented in /proc/sys\n * \t(incl. newline, etc), and copy it as a string into provided\n * \tby program buffer *buf* of size *buf_len*.\n *\n * \tThe whole value is copied, no matter what file position user\n * \tspace issued e.g. sys_read at.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n *\n * \t**-EINVAL** if current value was unavailable, e.g. because\n * \tsysctl is uninitialized and read returns -EIO for it.\n */\nstatic long (*bpf_sysctl_get_current_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 102;\n\n/*\n * bpf_sysctl_get_new_value\n *\n * \tGet new value being written by user space to sysctl (before\n * \tthe actual write happens) and copy it as a string into\n * \tprovided by program buffer *buf* of size *buf_len*.\n *\n * \tUser space may write new value at file position > 0.\n *\n * \tThe buffer is always NUL terminated, unless it's zero-sized.\n *\n * Returns\n * \tNumber of character copied (not including the trailing NUL).\n *\n * \t**-E2BIG** if the buffer wasn't big enough (*buf* will contain\n * \ttruncated name in this case).\n *\n * \t**-EINVAL** if sysctl is being read.\n */\nstatic long (*bpf_sysctl_get_new_value)(struct bpf_sysctl *ctx, char *buf, unsigned long buf_len) = (void *) 103;\n\n/*\n * bpf_sysctl_set_new_value\n *\n * \tOverride new value being written by user space to sysctl with\n * \tvalue provided by program in buffer *buf* of size *buf_len*.\n *\n * \t*buf* should contain a string in same form as provided by user\n * \tspace on sysctl write.\n *\n * \tUser space may write new value at file position > 0. To override\n * \tthe whole sysctl value file position should be set to zero.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-E2BIG** if the *buf_len* is too big.\n *\n * \t**-EINVAL** if sysctl is being read.\n */\nstatic long (*bpf_sysctl_set_new_value)(struct bpf_sysctl *ctx, const char *buf, unsigned long buf_len) = (void *) 104;\n\n/*\n * bpf_strtol\n *\n * \tConvert the initial part of the string from buffer *buf* of\n * \tsize *buf_len* to a long integer according to the given base\n * \tand save the result in *res*.\n *\n * \tThe string may begin with an arbitrary amount of white space\n * \t(as determined by **isspace**\\ (3)) followed by a single\n * \toptional '**-**' sign.\n *\n * \tFive least significant bits of *flags* encode base, other bits\n * \tare currently unused.\n *\n * \tBase must be either 8, 10, 16 or 0 to detect it automatically\n * \tsimilar to user space **strtol**\\ (3).\n *\n * Returns\n * \tNumber of characters consumed on success. Must be positive but\n * \tno more than *buf_len*.\n *\n * \t**-EINVAL** if no valid digits were found or unsupported base\n * \twas provided.\n *\n * \t**-ERANGE** if resulting value was out of range.\n */\nstatic long (*bpf_strtol)(const char *buf, unsigned long buf_len, __u64 flags, long *res) = (void *) 105;\n\n/*\n * bpf_strtoul\n *\n * \tConvert the initial part of the string from buffer *buf* of\n * \tsize *buf_len* to an unsigned long integer according to the\n * \tgiven base and save the result in *res*.\n *\n * \tThe string may begin with an arbitrary amount of white space\n * \t(as determined by **isspace**\\ (3)).\n *\n * \tFive least significant bits of *flags* encode base, other bits\n * \tare currently unused.\n *\n * \tBase must be either 8, 10, 16 or 0 to detect it automatically\n * \tsimilar to user space **strtoul**\\ (3).\n *\n * Returns\n * \tNumber of characters consumed on success. Must be positive but\n * \tno more than *buf_len*.\n *\n * \t**-EINVAL** if no valid digits were found or unsupported base\n * \twas provided.\n *\n * \t**-ERANGE** if resulting value was out of range.\n */\nstatic long (*bpf_strtoul)(const char *buf, unsigned long buf_len, __u64 flags, unsigned long *res) = (void *) 106;\n\n/*\n * bpf_sk_storage_get\n *\n * \tGet a bpf-local-storage from a *sk*.\n *\n * \tLogically, it could be thought of getting the value from\n * \ta *map* with *sk* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *sk*) except this\n * \thelper enforces the key must be a full socket and the map must\n * \tbe a **BPF_MAP_TYPE_SK_STORAGE** also.\n *\n * \tUnderneath, the value is stored locally at *sk* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf-local-storages residing at *sk*.\n *\n * \t*sk* is a kernel **struct sock** pointer for LSM program.\n * \t*sk* is a **struct bpf_sock** pointer for other program types.\n *\n * \tAn optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf-local-storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_SK_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf-local-storage.  If *value* is\n * \t**NULL**, the new bpf-local-storage will be zero initialized.\n *\n * Returns\n * \tA bpf-local-storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf-local-storage.\n */\nstatic void *(*bpf_sk_storage_get)(void *map, void *sk, void *value, __u64 flags) = (void *) 107;\n\n/*\n * bpf_sk_storage_delete\n *\n * \tDelete a bpf-local-storage from a *sk*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf-local-storage cannot be found.\n * \t**-EINVAL** if sk is not a fullsock (e.g. a request_sock).\n */\nstatic long (*bpf_sk_storage_delete)(void *map, void *sk) = (void *) 108;\n\n/*\n * bpf_send_signal\n *\n * \tSend signal *sig* to the process of the current task.\n * \tThe signal may be delivered to any of this process's threads.\n *\n * Returns\n * \t0 on success or successfully queued.\n *\n * \t**-EBUSY** if work queue under nmi is full.\n *\n * \t**-EINVAL** if *sig* is invalid.\n *\n * \t**-EPERM** if no permission to send the *sig*.\n *\n * \t**-EAGAIN** if bpf program can try again.\n */\nstatic long (*bpf_send_signal)(__u32 sig) = (void *) 109;\n\n/*\n * bpf_tcp_gen_syncookie\n *\n * \tTry to issue a SYN cookie for the packet with corresponding\n * \tIP/TCP headers, *iph* and *th*, on the listening socket in *sk*.\n *\n * \t*iph* points to the start of the IPv4 or IPv6 header, while\n * \t*iph_len* contains **sizeof**\\ (**struct iphdr**) or\n * \t**sizeof**\\ (**struct ip6hdr**).\n *\n * \t*th* points to the start of the TCP header, while *th_len*\n * \tcontains the length of the TCP header.\n *\n * Returns\n * \tOn success, lower 32 bits hold the generated SYN cookie in\n * \tfollowed by 16 bits which hold the MSS value for that cookie,\n * \tand the top 16 bits are unused.\n *\n * \tOn failure, the returned value is one of the following:\n *\n * \t**-EINVAL** SYN cookie cannot be issued due to error\n *\n * \t**-ENOENT** SYN cookie should not be issued (no SYN flood)\n *\n * \t**-EOPNOTSUPP** kernel configuration does not enable SYN cookies\n *\n * \t**-EPROTONOSUPPORT** IP packet version is not 4 or 6\n */\nstatic __s64 (*bpf_tcp_gen_syncookie)(void *sk, void *iph, __u32 iph_len, struct tcphdr *th, __u32 th_len) = (void *) 110;\n\n/*\n * bpf_skb_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \t*ctx* is a pointer to in-kernel struct sk_buff.\n *\n * \tThis helper is similar to **bpf_perf_event_output**\\ () but\n * \trestricted to raw_tracepoint bpf programs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_skb_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 111;\n\n/*\n * bpf_probe_read_user\n *\n * \tSafely attempt to read *size* bytes from user space address\n * \t*unsafe_ptr* and store the data in *dst*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read_user)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 112;\n\n/*\n * bpf_probe_read_kernel\n *\n * \tSafely attempt to read *size* bytes from kernel space address\n * \t*unsafe_ptr* and store the data in *dst*.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_probe_read_kernel)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 113;\n\n/*\n * bpf_probe_read_user_str\n *\n * \tCopy a NUL terminated string from an unsafe user address\n * \t*unsafe_ptr* to *dst*. The *size* should include the\n * \tterminating NUL byte. In case the string length is smaller than\n * \t*size*, the target is not padded with further NUL bytes. If the\n * \tstring length is larger than *size*, just *size*-1 bytes are\n * \tcopied and the last byte is set to NUL.\n *\n * \tOn success, returns the number of bytes that were written,\n * \tincluding the terminal NUL. This makes this helper useful in\n * \ttracing programs for reading strings, and more importantly to\n * \tget its length at runtime. See the following snippet:\n *\n * \t::\n *\n * \t\tSEC(\"kprobe/sys_open\")\n * \t\tvoid bpf_sys_open(struct pt_regs *ctx)\n * \t\t{\n * \t\t        char buf[PATHLEN]; // PATHLEN is defined to 256\n * \t\t        int res = bpf_probe_read_user_str(buf, sizeof(buf),\n * \t\t\t                                  ctx->di);\n *\n * \t\t\t// Consume buf, for example push it to\n * \t\t\t// userspace via bpf_perf_event_output(); we\n * \t\t\t// can use res (the string length) as event\n * \t\t\t// size, after checking its boundaries.\n * \t\t}\n *\n * \tIn comparison, using **bpf_probe_read_user**\\ () helper here\n * \tinstead to read the string would require to estimate the length\n * \tat compile time, and would often result in copying more memory\n * \tthan necessary.\n *\n * \tAnother useful use case is when parsing individual process\n * \targuments or individual environment variables navigating\n * \t*current*\\ **->mm->arg_start** and *current*\\\n * \t**->mm->env_start**: using this helper and the return value,\n * \tone can quickly iterate at the right offset of the memory area.\n *\n * Returns\n * \tOn success, the strictly positive length of the output string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_probe_read_user_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 114;\n\n/*\n * bpf_probe_read_kernel_str\n *\n * \tCopy a NUL terminated string from an unsafe kernel address *unsafe_ptr*\n * \tto *dst*. Same semantics as with **bpf_probe_read_user_str**\\ () apply.\n *\n * Returns\n * \tOn success, the strictly positive length of the string, including\n * \tthe trailing NUL character. On error, a negative value.\n */\nstatic long (*bpf_probe_read_kernel_str)(void *dst, __u32 size, const void *unsafe_ptr) = (void *) 115;\n\n/*\n * bpf_tcp_send_ack\n *\n * \tSend out a tcp-ack. *tp* is the in-kernel struct **tcp_sock**.\n * \t*rcv_nxt* is the ack_seq to be sent out.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_tcp_send_ack)(void *tp, __u32 rcv_nxt) = (void *) 116;\n\n/*\n * bpf_send_signal_thread\n *\n * \tSend signal *sig* to the thread corresponding to the current task.\n *\n * Returns\n * \t0 on success or successfully queued.\n *\n * \t**-EBUSY** if work queue under nmi is full.\n *\n * \t**-EINVAL** if *sig* is invalid.\n *\n * \t**-EPERM** if no permission to send the *sig*.\n *\n * \t**-EAGAIN** if bpf program can try again.\n */\nstatic long (*bpf_send_signal_thread)(__u32 sig) = (void *) 117;\n\n/*\n * bpf_jiffies64\n *\n * \tObtain the 64bit jiffies\n *\n * Returns\n * \tThe 64 bit jiffies\n */\nstatic __u64 (*bpf_jiffies64)(void) = (void *) 118;\n\n/*\n * bpf_read_branch_records\n *\n * \tFor an eBPF program attached to a perf event, retrieve the\n * \tbranch records (**struct perf_branch_entry**) associated to *ctx*\n * \tand store it in the buffer pointed by *buf* up to size\n * \t*size* bytes.\n *\n * Returns\n * \tOn success, number of bytes written to *buf*. On error, a\n * \tnegative value.\n *\n * \tThe *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to\n * \tinstead return the number of bytes required to store all the\n * \tbranch entries. If this flag is set, *buf* may be NULL.\n *\n * \t**-EINVAL** if arguments invalid or **size** not a multiple\n * \tof **sizeof**\\ (**struct perf_branch_entry**\\ ).\n *\n * \t**-ENOENT** if architecture does not support branch records.\n */\nstatic long (*bpf_read_branch_records)(struct bpf_perf_event_data *ctx, void *buf, __u32 size, __u64 flags) = (void *) 119;\n\n/*\n * bpf_get_ns_current_pid_tgid\n *\n * \tReturns 0 on success, values for *pid* and *tgid* as seen from the current\n * \t*namespace* will be returned in *nsdata*.\n *\n * Returns\n * \t0 on success, or one of the following in case of failure:\n *\n * \t**-EINVAL** if dev and inum supplied don't match dev_t and inode number\n * \twith nsfs of current task, or if dev conversion to dev_t lost high bits.\n *\n * \t**-ENOENT** if pidns does not exists for the current task.\n */\nstatic long (*bpf_get_ns_current_pid_tgid)(__u64 dev, __u64 ino, struct bpf_pidns_info *nsdata, __u32 size) = (void *) 120;\n\n/*\n * bpf_xdp_output\n *\n * \tWrite raw *data* blob into a special BPF perf event held by\n * \t*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf\n * \tevent must have the following attributes: **PERF_SAMPLE_RAW**\n * \tas **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and\n * \t**PERF_COUNT_SW_BPF_OUTPUT** as **config**.\n *\n * \tThe *flags* are used to indicate the index in *map* for which\n * \tthe value must be put, masked with **BPF_F_INDEX_MASK**.\n * \tAlternatively, *flags* can be set to **BPF_F_CURRENT_CPU**\n * \tto indicate that the index of the current CPU core should be\n * \tused.\n *\n * \tThe value to write, of *size*, is passed through eBPF stack and\n * \tpointed by *data*.\n *\n * \t*ctx* is a pointer to in-kernel struct xdp_buff.\n *\n * \tThis helper is similar to **bpf_perf_eventoutput**\\ () but\n * \trestricted to raw_tracepoint bpf programs.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_xdp_output)(void *ctx, void *map, __u64 flags, void *data, __u64 size) = (void *) 121;\n\n/*\n * bpf_get_netns_cookie\n *\n * \tRetrieve the cookie (generated by the kernel) of the network\n * \tnamespace the input *ctx* is associated with. The network\n * \tnamespace cookie remains stable for its lifetime and provides\n * \ta global identifier that can be assumed unique. If *ctx* is\n * \tNULL, then the helper returns the cookie for the initial\n * \tnetwork namespace. The cookie itself is very similar to that\n * \tof **bpf_get_socket_cookie**\\ () helper, but for network\n * \tnamespaces instead of sockets.\n *\n * Returns\n * \tA 8-byte long opaque number.\n */\nstatic __u64 (*bpf_get_netns_cookie)(void *ctx) = (void *) 122;\n\n/*\n * bpf_get_current_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of the cgroup associated\n * \twith the current task at the *ancestor_level*. The root cgroup\n * \tis at *ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with the current task, then return value will be the\n * \tsame as that of **bpf_get_current_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith the current task.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_get_current_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_get_current_ancestor_cgroup_id)(int ancestor_level) = (void *) 123;\n\n/*\n * bpf_sk_assign\n *\n * \tHelper is overloaded depending on BPF program type. This\n * \tdescription applies to **BPF_PROG_TYPE_SCHED_CLS** and\n * \t**BPF_PROG_TYPE_SCHED_ACT** programs.\n *\n * \tAssign the *sk* to the *skb*. When combined with appropriate\n * \trouting configuration to receive the packet towards the socket,\n * \twill cause *skb* to be delivered to the specified socket.\n * \tSubsequent redirection of *skb* via  **bpf_redirect**\\ (),\n * \t**bpf_clone_redirect**\\ () or other methods outside of BPF may\n * \tinterfere with successful delivery to the socket.\n *\n * \tThis operation is only valid from TC ingress path.\n *\n * \tThe *flags* argument must be zero.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EINVAL** if specified *flags* are not supported.\n *\n * \t**-ENOENT** if the socket is unavailable for assignment.\n *\n * \t**-ENETUNREACH** if the socket is unreachable (wrong netns).\n *\n * \t**-EOPNOTSUPP** if the operation is not supported, for example\n * \ta call from outside of TC ingress.\n *\n * \t**-ESOCKTNOSUPPORT** if the socket type is not supported\n * \t(reuseport).\n */\nstatic long (*bpf_sk_assign)(void *ctx, void *sk, __u64 flags) = (void *) 124;\n\n/*\n * bpf_ktime_get_boot_ns\n *\n * \tReturn the time elapsed since system boot, in nanoseconds.\n * \tDoes include the time the system was suspended.\n * \tSee: **clock_gettime**\\ (**CLOCK_BOOTTIME**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_boot_ns)(void) = (void *) 125;\n\n/*\n * bpf_seq_printf\n *\n * \t**bpf_seq_printf**\\ () uses seq_file **seq_printf**\\ () to print\n * \tout the format string.\n * \tThe *m* represents the seq_file. The *fmt* and *fmt_size* are for\n * \tthe format string itself. The *data* and *data_len* are format string\n * \targuments. The *data* are a **u64** array and corresponding format string\n * \tvalues are stored in the array. For strings and pointers where pointees\n * \tare accessed, only the pointer values are stored in the *data* array.\n * \tThe *data_len* is the size of *data* in bytes.\n *\n * \tFormats **%s**, **%p{i,I}{4,6}** requires to read kernel memory.\n * \tReading kernel memory may fail due to either invalid address or\n * \tvalid address but requiring a major memory fault. If reading kernel memory\n * \tfails, the string for **%s** will be an empty string, and the ip\n * \taddress for **%p{i,I}{4,6}** will be 0. Not returning error to\n * \tbpf program is consistent with what **bpf_trace_printk**\\ () does for now.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EBUSY** if per-CPU memory copy buffer is busy, can try again\n * \tby returning 1 from bpf program.\n *\n * \t**-EINVAL** if arguments are invalid, or if *fmt* is invalid/unsupported.\n *\n * \t**-E2BIG** if *fmt* contains too many format specifiers.\n *\n * \t**-EOVERFLOW** if an overflow happened: The same object will be tried again.\n */\nstatic long (*bpf_seq_printf)(struct seq_file *m, const char *fmt, __u32 fmt_size, const void *data, __u32 data_len) = (void *) 126;\n\n/*\n * bpf_seq_write\n *\n * \t**bpf_seq_write**\\ () uses seq_file **seq_write**\\ () to write the data.\n * \tThe *m* represents the seq_file. The *data* and *len* represent the\n * \tdata to write in bytes.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure:\n *\n * \t**-EOVERFLOW** if an overflow happened: The same object will be tried again.\n */\nstatic long (*bpf_seq_write)(struct seq_file *m, const void *data, __u32 len) = (void *) 127;\n\n/*\n * bpf_sk_cgroup_id\n *\n * \tReturn the cgroup v2 id of the socket *sk*.\n *\n * \t*sk* must be a non-**NULL** pointer to a socket, e.g. one\n * \treturned from **bpf_sk_lookup_xxx**\\ (),\n * \t**bpf_sk_fullsock**\\ (), etc. The format of returned id is\n * \tsame as in **bpf_skb_cgroup_id**\\ ().\n *\n * \tThis helper is available only if the kernel was compiled with\n * \tthe **CONFIG_SOCK_CGROUP_DATA** configuration option.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_sk_cgroup_id)(void *sk) = (void *) 128;\n\n/*\n * bpf_sk_ancestor_cgroup_id\n *\n * \tReturn id of cgroup v2 that is ancestor of cgroup associated\n * \twith the *sk* at the *ancestor_level*.  The root cgroup is at\n * \t*ancestor_level* zero and each step down the hierarchy\n * \tincrements the level. If *ancestor_level* == level of cgroup\n * \tassociated with *sk*, then return value will be same as that\n * \tof **bpf_sk_cgroup_id**\\ ().\n *\n * \tThe helper is useful to implement policies based on cgroups\n * \tthat are upper in hierarchy than immediate cgroup associated\n * \twith *sk*.\n *\n * \tThe format of returned id and helper limitations are same as in\n * \t**bpf_sk_cgroup_id**\\ ().\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_sk_ancestor_cgroup_id)(void *sk, int ancestor_level) = (void *) 129;\n\n/*\n * bpf_ringbuf_output\n *\n * \tCopy *size* bytes from *data* into a ring buffer *ringbuf*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tAn adaptive notification is a notification sent whenever the user-space\n * \tprocess has caught up and consumed all available payloads. In case the user-space\n * \tprocess is still processing a previous payload, then no notification is needed\n * \tas it will process the newly added payload automatically.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_ringbuf_output)(void *ringbuf, void *data, __u64 size, __u64 flags) = (void *) 130;\n\n/*\n * bpf_ringbuf_reserve\n *\n * \tReserve *size* bytes of payload in a ring buffer *ringbuf*.\n * \t*flags* must be 0.\n *\n * Returns\n * \tValid pointer with *size* bytes of memory available; NULL,\n * \totherwise.\n */\nstatic void *(*bpf_ringbuf_reserve)(void *ringbuf, __u64 size, __u64 flags) = (void *) 131;\n\n/*\n * bpf_ringbuf_submit\n *\n * \tSubmit reserved ring buffer sample, pointed to by *data*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tSee 'bpf_ringbuf_output()' for the definition of adaptive notification.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_submit)(void *data, __u64 flags) = (void *) 132;\n\n/*\n * bpf_ringbuf_discard\n *\n * \tDiscard reserved ring buffer sample, pointed to by *data*.\n * \tIf **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification\n * \tof new data availability is sent.\n * \tIf **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification\n * \tof new data availability is sent unconditionally.\n * \tIf **0** is specified in *flags*, an adaptive notification\n * \tof new data availability is sent.\n *\n * \tSee 'bpf_ringbuf_output()' for the definition of adaptive notification.\n *\n * Returns\n * \tNothing. Always succeeds.\n */\nstatic void (*bpf_ringbuf_discard)(void *data, __u64 flags) = (void *) 133;\n\n/*\n * bpf_ringbuf_query\n *\n * \tQuery various characteristics of provided ring buffer. What\n * \texactly is queries is determined by *flags*:\n *\n * \t* **BPF_RB_AVAIL_DATA**: Amount of data not yet consumed.\n * \t* **BPF_RB_RING_SIZE**: The size of ring buffer.\n * \t* **BPF_RB_CONS_POS**: Consumer position (can wrap around).\n * \t* **BPF_RB_PROD_POS**: Producer(s) position (can wrap around).\n *\n * \tData returned is just a momentary snapshot of actual values\n * \tand could be inaccurate, so this facility should be used to\n * \tpower heuristics and for reporting, not to make 100% correct\n * \tcalculation.\n *\n * Returns\n * \tRequested value, or 0, if *flags* are not recognized.\n */\nstatic __u64 (*bpf_ringbuf_query)(void *ringbuf, __u64 flags) = (void *) 134;\n\n/*\n * bpf_csum_level\n *\n * \tChange the skbs checksum level by one layer up or down, or\n * \treset it entirely to none in order to have the stack perform\n * \tchecksum validation. The level is applicable to the following\n * \tprotocols: TCP, UDP, GRE, SCTP, FCOE. For example, a decap of\n * \t| ETH | IP | UDP | GUE | IP | TCP | into | ETH | IP | TCP |\n * \tthrough **bpf_skb_adjust_room**\\ () helper with passing in\n * \t**BPF_F_ADJ_ROOM_NO_CSUM_RESET** flag would require one\tcall\n * \tto **bpf_csum_level**\\ () with **BPF_CSUM_LEVEL_DEC** since\n * \tthe UDP header is removed. Similarly, an encap of the latter\n * \tinto the former could be accompanied by a helper call to\n * \t**bpf_csum_level**\\ () with **BPF_CSUM_LEVEL_INC** if the\n * \tskb is still intended to be processed in higher layers of the\n * \tstack instead of just egressing at tc.\n *\n * \tThere are three supported level settings at this time:\n *\n * \t* **BPF_CSUM_LEVEL_INC**: Increases skb->csum_level for skbs\n * \t  with CHECKSUM_UNNECESSARY.\n * \t* **BPF_CSUM_LEVEL_DEC**: Decreases skb->csum_level for skbs\n * \t  with CHECKSUM_UNNECESSARY.\n * \t* **BPF_CSUM_LEVEL_RESET**: Resets skb->csum_level to 0 and\n * \t  sets CHECKSUM_NONE to force checksum validation by the stack.\n * \t* **BPF_CSUM_LEVEL_QUERY**: No-op, returns the current\n * \t  skb->csum_level.\n *\n * Returns\n * \t0 on success, or a negative error in case of failure. In the\n * \tcase of **BPF_CSUM_LEVEL_QUERY**, the current skb->csum_level\n * \tis returned or the error code -EACCES in case the skb is not\n * \tsubject to CHECKSUM_UNNECESSARY.\n */\nstatic long (*bpf_csum_level)(struct __sk_buff *skb, __u64 level) = (void *) 135;\n\n/*\n * bpf_skc_to_tcp6_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp6_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp6_sock *(*bpf_skc_to_tcp6_sock)(void *sk) = (void *) 136;\n\n/*\n * bpf_skc_to_tcp_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_sock *(*bpf_skc_to_tcp_sock)(void *sk) = (void *) 137;\n\n/*\n * bpf_skc_to_tcp_timewait_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_timewait_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_timewait_sock *(*bpf_skc_to_tcp_timewait_sock)(void *sk) = (void *) 138;\n\n/*\n * bpf_skc_to_tcp_request_sock\n *\n * \tDynamically cast a *sk* pointer to a *tcp_request_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct tcp_request_sock *(*bpf_skc_to_tcp_request_sock)(void *sk) = (void *) 139;\n\n/*\n * bpf_skc_to_udp6_sock\n *\n * \tDynamically cast a *sk* pointer to a *udp6_sock* pointer.\n *\n * Returns\n * \t*sk* if casting is valid, or **NULL** otherwise.\n */\nstatic struct udp6_sock *(*bpf_skc_to_udp6_sock)(void *sk) = (void *) 140;\n\n/*\n * bpf_get_task_stack\n *\n * \tReturn a user or a kernel stack in bpf program provided buffer.\n * \tTo achieve this, the helper needs *task*, which is a valid\n * \tpointer to **struct task_struct**. To store the stacktrace, the\n * \tbpf program provides *buf* with a nonnegative *size*.\n *\n * \tThe last argument, *flags*, holds the number of stack frames to\n * \tskip (from 0 to 255), masked with\n * \t**BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set\n * \tthe following flags:\n *\n * \t**BPF_F_USER_STACK**\n * \t\tCollect a user space stack instead of a kernel stack.\n * \t**BPF_F_USER_BUILD_ID**\n * \t\tCollect buildid+offset instead of ips for user stack,\n * \t\tonly valid if **BPF_F_USER_STACK** is also specified.\n *\n * \t**bpf_get_task_stack**\\ () can collect up to\n * \t**PERF_MAX_STACK_DEPTH** both kernel and user frames, subject\n * \tto sufficient large buffer size. Note that\n * \tthis limit can be controlled with the **sysctl** program, and\n * \tthat it should be manually increased in order to profile long\n * \tuser stacks (such as stacks for Java programs). To do so, use:\n *\n * \t::\n *\n * \t\t# sysctl kernel.perf_event_max_stack=<new value>\n *\n * Returns\n * \tA non-negative value equal to or less than *size* on success,\n * \tor a negative error in case of failure.\n */\nstatic long (*bpf_get_task_stack)(struct task_struct *task, void *buf, __u32 size, __u64 flags) = (void *) 141;\n\n/*\n * bpf_load_hdr_opt\n *\n * \tLoad header option.  Support reading a particular TCP header\n * \toption for bpf program (**BPF_PROG_TYPE_SOCK_OPS**).\n *\n * \tIf *flags* is 0, it will search the option from the\n * \t*skops*\\ **->skb_data**.  The comment in **struct bpf_sock_ops**\n * \thas details on what skb_data contains under different\n * \t*skops*\\ **->op**.\n *\n * \tThe first byte of the *searchby_res* specifies the\n * \tkind that it wants to search.\n *\n * \tIf the searching kind is an experimental kind\n * \t(i.e. 253 or 254 according to RFC6994).  It also\n * \tneeds to specify the \"magic\" which is either\n * \t2 bytes or 4 bytes.  It then also needs to\n * \tspecify the size of the magic by using\n * \tthe 2nd byte which is \"kind-length\" of a TCP\n * \theader option and the \"kind-length\" also\n * \tincludes the first 2 bytes \"kind\" and \"kind-length\"\n * \titself as a normal TCP header option also does.\n *\n * \tFor example, to search experimental kind 254 with\n * \t2 byte magic 0xeB9F, the searchby_res should be\n * \t[ 254, 4, 0xeB, 0x9F, 0, 0, .... 0 ].\n *\n * \tTo search for the standard window scale option (3),\n * \tthe *searchby_res* should be [ 3, 0, 0, .... 0 ].\n * \tNote, kind-length must be 0 for regular option.\n *\n * \tSearching for No-Op (0) and End-of-Option-List (1) are\n * \tnot supported.\n *\n * \t*len* must be at least 2 bytes which is the minimal size\n * \tof a header option.\n *\n * \tSupported flags:\n *\n * \t* **BPF_LOAD_HDR_OPT_TCP_SYN** to search from the\n * \t  saved_syn packet or the just-received syn packet.\n *\n *\n * Returns\n * \t> 0 when found, the header option is copied to *searchby_res*.\n * \tThe return value is the total length copied. On failure, a\n * \tnegative error code is returned:\n *\n * \t**-EINVAL** if a parameter is invalid.\n *\n * \t**-ENOMSG** if the option is not found.\n *\n * \t**-ENOENT** if no syn packet is available when\n * \t**BPF_LOAD_HDR_OPT_TCP_SYN** is used.\n *\n * \t**-ENOSPC** if there is not enough space.  Only *len* number of\n * \tbytes are copied.\n *\n * \t**-EFAULT** on failure to parse the header options in the\n * \tpacket.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_load_hdr_opt)(struct bpf_sock_ops *skops, void *searchby_res, __u32 len, __u64 flags) = (void *) 142;\n\n/*\n * bpf_store_hdr_opt\n *\n * \tStore header option.  The data will be copied\n * \tfrom buffer *from* with length *len* to the TCP header.\n *\n * \tThe buffer *from* should have the whole option that\n * \tincludes the kind, kind-length, and the actual\n * \toption data.  The *len* must be at least kind-length\n * \tlong.  The kind-length does not have to be 4 byte\n * \taligned.  The kernel will take care of the padding\n * \tand setting the 4 bytes aligned value to th->doff.\n *\n * \tThis helper will check for duplicated option\n * \tby searching the same option in the outgoing skb.\n *\n * \tThis helper can only be called during\n * \t**BPF_SOCK_OPS_WRITE_HDR_OPT_CB**.\n *\n *\n * Returns\n * \t0 on success, or negative error in case of failure:\n *\n * \t**-EINVAL** If param is invalid.\n *\n * \t**-ENOSPC** if there is not enough space in the header.\n * \tNothing has been written\n *\n * \t**-EEXIST** if the option already exists.\n *\n * \t**-EFAULT** on failrue to parse the existing header options.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_store_hdr_opt)(struct bpf_sock_ops *skops, const void *from, __u32 len, __u64 flags) = (void *) 143;\n\n/*\n * bpf_reserve_hdr_opt\n *\n * \tReserve *len* bytes for the bpf header option.  The\n * \tspace will be used by **bpf_store_hdr_opt**\\ () later in\n * \t**BPF_SOCK_OPS_WRITE_HDR_OPT_CB**.\n *\n * \tIf **bpf_reserve_hdr_opt**\\ () is called multiple times,\n * \tthe total number of bytes will be reserved.\n *\n * \tThis helper can only be called during\n * \t**BPF_SOCK_OPS_HDR_OPT_LEN_CB**.\n *\n *\n * Returns\n * \t0 on success, or negative error in case of failure:\n *\n * \t**-EINVAL** if a parameter is invalid.\n *\n * \t**-ENOSPC** if there is not enough space in the header.\n *\n * \t**-EPERM** if the helper cannot be used under the current\n * \t*skops*\\ **->op**.\n */\nstatic long (*bpf_reserve_hdr_opt)(struct bpf_sock_ops *skops, __u32 len, __u64 flags) = (void *) 144;\n\n/*\n * bpf_inode_storage_get\n *\n * \tGet a bpf_local_storage from an *inode*.\n *\n * \tLogically, it could be thought of as getting the value from\n * \ta *map* with *inode* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *inode*) except this\n * \thelper enforces the key must be an inode and the map must also\n * \tbe a **BPF_MAP_TYPE_INODE_STORAGE**.\n *\n * \tUnderneath, the value is stored locally at *inode* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf_local_storage residing at *inode*.\n *\n * \tAn optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf_local_storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf_local_storage.  If *value* is\n * \t**NULL**, the new bpf_local_storage will be zero initialized.\n *\n * Returns\n * \tA bpf_local_storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf_local_storage.\n */\nstatic void *(*bpf_inode_storage_get)(void *map, void *inode, void *value, __u64 flags) = (void *) 145;\n\n/*\n * bpf_inode_storage_delete\n *\n * \tDelete a bpf_local_storage from an *inode*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf_local_storage cannot be found.\n */\nstatic int (*bpf_inode_storage_delete)(void *map, void *inode) = (void *) 146;\n\n/*\n * bpf_d_path\n *\n * \tReturn full path for given **struct path** object, which\n * \tneeds to be the kernel BTF *path* object. The path is\n * \treturned in the provided buffer *buf* of size *sz* and\n * \tis zero terminated.\n *\n *\n * Returns\n * \tOn success, the strictly positive length of the string,\n * \tincluding the trailing NUL character. On error, a negative\n * \tvalue.\n */\nstatic long (*bpf_d_path)(struct path *path, char *buf, __u32 sz) = (void *) 147;\n\n/*\n * bpf_copy_from_user\n *\n * \tRead *size* bytes from user space address *user_ptr* and store\n * \tthe data in *dst*. This is a wrapper of **copy_from_user**\\ ().\n *\n * Returns\n * \t0 on success, or a negative error in case of failure.\n */\nstatic long (*bpf_copy_from_user)(void *dst, __u32 size, const void *user_ptr) = (void *) 148;\n\n/*\n * bpf_snprintf_btf\n *\n * \tUse BTF to store a string representation of *ptr*->ptr in *str*,\n * \tusing *ptr*->type_id.  This value should specify the type\n * \tthat *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1)\n * \tcan be used to look up vmlinux BTF type ids. Traversing the\n * \tdata structure using BTF, the type information and values are\n * \tstored in the first *str_size* - 1 bytes of *str*.  Safe copy of\n * \tthe pointer data is carried out to avoid kernel crashes during\n * \toperation.  Smaller types can use string space on the stack;\n * \tlarger programs can use map data to store the string\n * \trepresentation.\n *\n * \tThe string can be subsequently shared with userspace via\n * \tbpf_perf_event_output() or ring buffer interfaces.\n * \tbpf_trace_printk() is to be avoided as it places too small\n * \ta limit on string size to be useful.\n *\n * \t*flags* is a combination of\n *\n * \t**BTF_F_COMPACT**\n * \t\tno formatting around type information\n * \t**BTF_F_NONAME**\n * \t\tno struct/union member names/types\n * \t**BTF_F_PTR_RAW**\n * \t\tshow raw (unobfuscated) pointer values;\n * \t\tequivalent to printk specifier %px.\n * \t**BTF_F_ZERO**\n * \t\tshow zero-valued struct/union members; they\n * \t\tare not displayed by default\n *\n *\n * Returns\n * \tThe number of bytes that were written (or would have been\n * \twritten if output had to be truncated due to string size),\n * \tor a negative error in cases of failure.\n */\nstatic long (*bpf_snprintf_btf)(char *str, __u32 str_size, struct btf_ptr *ptr, __u32 btf_ptr_size, __u64 flags) = (void *) 149;\n\n/*\n * bpf_seq_printf_btf\n *\n * \tUse BTF to write to seq_write a string representation of\n * \t*ptr*->ptr, using *ptr*->type_id as per bpf_snprintf_btf().\n * \t*flags* are identical to those used for bpf_snprintf_btf.\n *\n * Returns\n * \t0 on success or a negative error in case of failure.\n */\nstatic long (*bpf_seq_printf_btf)(struct seq_file *m, struct btf_ptr *ptr, __u32 ptr_size, __u64 flags) = (void *) 150;\n\n/*\n * bpf_skb_cgroup_classid\n *\n * \tSee **bpf_get_cgroup_classid**\\ () for the main description.\n * \tThis helper differs from **bpf_get_cgroup_classid**\\ () in that\n * \tthe cgroup v1 net_cls class is retrieved only from the *skb*'s\n * \tassociated socket instead of the current process.\n *\n * Returns\n * \tThe id is returned or 0 in case the id could not be retrieved.\n */\nstatic __u64 (*bpf_skb_cgroup_classid)(struct __sk_buff *skb) = (void *) 151;\n\n/*\n * bpf_redirect_neigh\n *\n * \tRedirect the packet to another net device of index *ifindex*\n * \tand fill in L2 addresses from neighboring subsystem. This helper\n * \tis somewhat similar to **bpf_redirect**\\ (), except that it\n * \tpopulates L2 addresses as well, meaning, internally, the helper\n * \trelies on the neighbor lookup for the L2 address of the nexthop.\n *\n * \tThe helper will perform a FIB lookup based on the skb's\n * \tnetworking header to get the address of the next hop, unless\n * \tthis is supplied by the caller in the *params* argument. The\n * \t*plen* argument indicates the len of *params* and should be set\n * \tto 0 if *params* is NULL.\n *\n * \tThe *flags* argument is reserved and must be 0. The helper is\n * \tcurrently only supported for tc BPF program types, and enabled\n * \tfor IPv4 and IPv6 protocols.\n *\n * Returns\n * \tThe helper returns **TC_ACT_REDIRECT** on success or\n * \t**TC_ACT_SHOT** on error.\n */\nstatic long (*bpf_redirect_neigh)(__u32 ifindex, struct bpf_redir_neigh *params, int plen, __u64 flags) = (void *) 152;\n\n/*\n * bpf_per_cpu_ptr\n *\n * \tTake a pointer to a percpu ksym, *percpu_ptr*, and return a\n * \tpointer to the percpu kernel variable on *cpu*. A ksym is an\n * \textern variable decorated with '__ksym'. For ksym, there is a\n * \tglobal var (either static or global) defined of the same name\n * \tin the kernel. The ksym is percpu if the global var is percpu.\n * \tThe returned pointer points to the global percpu var on *cpu*.\n *\n * \tbpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the\n * \tkernel, except that bpf_per_cpu_ptr() may return NULL. This\n * \thappens if *cpu* is larger than nr_cpu_ids. The caller of\n * \tbpf_per_cpu_ptr() must check the returned value.\n *\n * Returns\n * \tA pointer pointing to the kernel percpu variable on *cpu*, or\n * \tNULL, if *cpu* is invalid.\n */\nstatic void *(*bpf_per_cpu_ptr)(const void *percpu_ptr, __u32 cpu) = (void *) 153;\n\n/*\n * bpf_this_cpu_ptr\n *\n * \tTake a pointer to a percpu ksym, *percpu_ptr*, and return a\n * \tpointer to the percpu kernel variable on this cpu. See the\n * \tdescription of 'ksym' in **bpf_per_cpu_ptr**\\ ().\n *\n * \tbpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in\n * \tthe kernel. Different from **bpf_per_cpu_ptr**\\ (), it would\n * \tnever return NULL.\n *\n * Returns\n * \tA pointer pointing to the kernel percpu variable on this cpu.\n */\nstatic void *(*bpf_this_cpu_ptr)(const void *percpu_ptr) = (void *) 154;\n\n/*\n * bpf_redirect_peer\n *\n * \tRedirect the packet to another net device of index *ifindex*.\n * \tThis helper is somewhat similar to **bpf_redirect**\\ (), except\n * \tthat the redirection happens to the *ifindex*' peer device and\n * \tthe netns switch takes place from ingress to ingress without\n * \tgoing through the CPU's backlog queue.\n *\n * \tThe *flags* argument is reserved and must be 0. The helper is\n * \tcurrently only supported for tc BPF program types at the ingress\n * \thook and for veth device types. The peer device must reside in a\n * \tdifferent network namespace.\n *\n * Returns\n * \tThe helper returns **TC_ACT_REDIRECT** on success or\n * \t**TC_ACT_SHOT** on error.\n */\nstatic long (*bpf_redirect_peer)(__u32 ifindex, __u64 flags) = (void *) 155;\n\n/*\n * bpf_task_storage_get\n *\n * \tGet a bpf_local_storage from the *task*.\n *\n * \tLogically, it could be thought of as getting the value from\n * \ta *map* with *task* as the **key**.  From this\n * \tperspective,  the usage is not much different from\n * \t**bpf_map_lookup_elem**\\ (*map*, **&**\\ *task*) except this\n * \thelper enforces the key must be an task_struct and the map must also\n * \tbe a **BPF_MAP_TYPE_TASK_STORAGE**.\n *\n * \tUnderneath, the value is stored locally at *task* instead of\n * \tthe *map*.  The *map* is used as the bpf-local-storage\n * \t\"type\". The bpf-local-storage \"type\" (i.e. the *map*) is\n * \tsearched against all bpf_local_storage residing at *task*.\n *\n * \tAn optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be\n * \tused such that a new bpf_local_storage will be\n * \tcreated if one does not exist.  *value* can be used\n * \ttogether with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify\n * \tthe initial value of a bpf_local_storage.  If *value* is\n * \t**NULL**, the new bpf_local_storage will be zero initialized.\n *\n * Returns\n * \tA bpf_local_storage pointer is returned on success.\n *\n * \t**NULL** if not found or there was an error in adding\n * \ta new bpf_local_storage.\n */\nstatic void *(*bpf_task_storage_get)(void *map, struct task_struct *task, void *value, __u64 flags) = (void *) 156;\n\n/*\n * bpf_task_storage_delete\n *\n * \tDelete a bpf_local_storage from a *task*.\n *\n * Returns\n * \t0 on success.\n *\n * \t**-ENOENT** if the bpf_local_storage cannot be found.\n */\nstatic long (*bpf_task_storage_delete)(void *map, struct task_struct *task) = (void *) 157;\n\n/*\n * bpf_get_current_task_btf\n *\n * \tReturn a BTF pointer to the \"current\" task.\n * \tThis pointer can also be used in helpers that accept an\n * \t*ARG_PTR_TO_BTF_ID* of type *task_struct*.\n *\n * Returns\n * \tPointer to the current task.\n */\nstatic struct task_struct *(*bpf_get_current_task_btf)(void) = (void *) 158;\n\n/*\n * bpf_bprm_opts_set\n *\n * \tSet or clear certain options on *bprm*:\n *\n * \t**BPF_F_BPRM_SECUREEXEC** Set the secureexec bit\n * \twhich sets the **AT_SECURE** auxv for glibc. The bit\n * \tis cleared if the flag is not specified.\n *\n * Returns\n * \t**-EINVAL** if invalid *flags* are passed, zero otherwise.\n */\nstatic long (*bpf_bprm_opts_set)(struct linux_binprm *bprm, __u64 flags) = (void *) 159;\n\n/*\n * bpf_ktime_get_coarse_ns\n *\n * \tReturn a coarse-grained version of the time elapsed since\n * \tsystem boot, in nanoseconds. Does not include time the system\n * \twas suspended.\n *\n * \tSee: **clock_gettime**\\ (**CLOCK_MONOTONIC_COARSE**)\n *\n * Returns\n * \tCurrent *ktime*.\n */\nstatic __u64 (*bpf_ktime_get_coarse_ns)(void) = (void *) 160;\n\n/*\n * bpf_ima_inode_hash\n *\n * \tReturns the stored IMA hash of the *inode* (if it's avaialable).\n * \tIf the hash is larger than *size*, then only *size*\n * \tbytes will be copied to *dst*\n *\n * Returns\n * \tThe **hash_algo** is returned on success,\n * \t**-EOPNOTSUP** if IMA is disabled or **-EINVAL** if\n * \tinvalid arguments are passed.\n */\nstatic long (*bpf_ima_inode_hash)(struct inode *inode, void *dst, __u32 size) = (void *) 161;\n\n/*\n * bpf_sock_from_file\n *\n * \tIf the given file represents a socket, returns the associated\n * \tsocket.\n *\n * Returns\n * \tA pointer to a struct socket on success or NULL if the file is\n * \tnot a socket.\n */\nstatic struct socket *(*bpf_sock_from_file)(struct file *file) = (void *) 162;\n\n/*\n * bpf_check_mtu\n *\n * \tCheck packet size against exceeding MTU of net device (based\n * \ton *ifindex*).  This helper will likely be used in combination\n * \twith helpers that adjust/change the packet size.\n *\n * \tThe argument *len_diff* can be used for querying with a planned\n * \tsize change. This allows to check MTU prior to changing packet\n * \tctx. Providing an *len_diff* adjustment that is larger than the\n * \tactual packet size (resulting in negative packet size) will in\n * \tprinciple not exceed the MTU, why it is not considered a\n * \tfailure.  Other BPF-helpers are needed for performing the\n * \tplanned size change, why the responsability for catch a negative\n * \tpacket size belong in those helpers.\n *\n * \tSpecifying *ifindex* zero means the MTU check is performed\n * \tagainst the current net device.  This is practical if this isn't\n * \tused prior to redirect.\n *\n * \tOn input *mtu_len* must be a valid pointer, else verifier will\n * \treject BPF program.  If the value *mtu_len* is initialized to\n * \tzero then the ctx packet size is use.  When value *mtu_len* is\n * \tprovided as input this specify the L3 length that the MTU check\n * \tis done against. Remember XDP and TC length operate at L2, but\n * \tthis value is L3 as this correlate to MTU and IP-header tot_len\n * \tvalues which are L3 (similar behavior as bpf_fib_lookup).\n *\n * \tThe Linux kernel route table can configure MTUs on a more\n * \tspecific per route level, which is not provided by this helper.\n * \tFor route level MTU checks use the **bpf_fib_lookup**\\ ()\n * \thelper.\n *\n * \t*ctx* is either **struct xdp_md** for XDP programs or\n * \t**struct sk_buff** for tc cls_act programs.\n *\n * \tThe *flags* argument can be a combination of one or more of the\n * \tfollowing values:\n *\n * \t**BPF_MTU_CHK_SEGS**\n * \t\tThis flag will only works for *ctx* **struct sk_buff**.\n * \t\tIf packet context contains extra packet segment buffers\n * \t\t(often knows as GSO skb), then MTU check is harder to\n * \t\tcheck at this point, because in transmit path it is\n * \t\tpossible for the skb packet to get re-segmented\n * \t\t(depending on net device features).  This could still be\n * \t\ta MTU violation, so this flag enables performing MTU\n * \t\tcheck against segments, with a different violation\n * \t\treturn code to tell it apart. Check cannot use len_diff.\n *\n * \tOn return *mtu_len* pointer contains the MTU value of the net\n * \tdevice.  Remember the net device configured MTU is the L3 size,\n * \twhich is returned here and XDP and TC length operate at L2.\n * \tHelper take this into account for you, but remember when using\n * \tMTU value in your BPF-code.\n *\n *\n * Returns\n * \t* 0 on success, and populate MTU value in *mtu_len* pointer.\n *\n * \t* < 0 if any input argument is invalid (*mtu_len* not updated)\n *\n * \tMTU violations return positive values, but also populate MTU\n * \tvalue in *mtu_len* pointer, as this can be needed for\n * \timplementing PMTU handing:\n *\n * \t* **BPF_MTU_CHK_RET_FRAG_NEEDED**\n * \t* **BPF_MTU_CHK_RET_SEGS_TOOBIG**\n */\nstatic long (*bpf_check_mtu)(void *ctx, __u32 ifindex, __u32 *mtu_len, __s32 len_diff, __u64 flags) = (void *) 163;\n\n/*\n * bpf_for_each_map_elem\n *\n * \tFor each element in **map**, call **callback_fn** function with\n * \t**map**, **callback_ctx** and other map-specific parameters.\n * \tThe **callback_fn** should be a static function and\n * \tthe **callback_ctx** should be a pointer to the stack.\n * \tThe **flags** is used to control certain aspects of the helper.\n * \tCurrently, the **flags** must be 0.\n *\n * \tThe following are a list of supported map types and their\n * \trespective expected callback signatures:\n *\n * \tBPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH,\n * \tBPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH,\n * \tBPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY\n *\n * \tlong (\\*callback_fn)(struct bpf_map \\*map, const void \\*key, void \\*value, void \\*ctx);\n *\n * \tFor per_cpu maps, the map_value is the value on the cpu where the\n * \tbpf_prog is running.\n *\n * \tIf **callback_fn** return 0, the helper will continue to the next\n * \telement. If return value is 1, the helper will skip the rest of\n * \telements and return. Other return values are not used now.\n *\n *\n * Returns\n * \tThe number of traversed map elements for success, **-EINVAL** for\n * \tinvalid **flags**.\n */\nstatic long (*bpf_for_each_map_elem)(void *map, void *callback_fn, void *callback_ctx, __u64 flags) = (void *) 164;\n\n/*\n * bpf_snprintf\n *\n * \tOutputs a string into the **str** buffer of size **str_size**\n * \tbased on a format string stored in a read-only map pointed by\n * \t**fmt**.\n *\n * \tEach format specifier in **fmt** corresponds to one u64 element\n * \tin the **data** array. For strings and pointers where pointees\n * \tare accessed, only the pointer values are stored in the *data*\n * \tarray. The *data_len* is the size of *data* in bytes.\n *\n * \tFormats **%s** and **%p{i,I}{4,6}** require to read kernel\n * \tmemory. Reading kernel memory may fail due to either invalid\n * \taddress or valid address but requiring a major memory fault. If\n * \treading kernel memory fails, the string for **%s** will be an\n * \tempty string, and the ip address for **%p{i,I}{4,6}** will be 0.\n * \tNot returning error to bpf program is consistent with what\n * \t**bpf_trace_printk**\\ () does for now.\n *\n *\n * Returns\n * \tThe strictly positive length of the formatted string, including\n * \tthe trailing zero character. If the return value is greater than\n * \t**str_size**, **str** contains a truncated string, guaranteed to\n * \tbe zero-terminated except when **str_size** is 0.\n *\n * \tOr **-EBUSY** if the per-CPU memory copy buffer is busy.\n */\nstatic long (*bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165;\n\n/*\n * bpf_sys_bpf\n *\n * \tExecute bpf syscall with given arguments.\n *\n * Returns\n * \tA syscall result.\n */\nstatic long (*bpf_sys_bpf)(__u32 cmd, void *attr, __u32 attr_size) = (void *) 166;\n\n/*\n * bpf_btf_find_by_name_kind\n *\n * \tFind BTF type with given name and kind in vmlinux BTF or in module's BTFs.\n *\n * Returns\n * \tReturns btf_id and btf_obj_fd in lower and upper 32 bits.\n */\nstatic long (*bpf_btf_find_by_name_kind)(char *name, int name_sz, __u32 kind, int flags) = (void *) 167;\n\n/*\n * bpf_sys_close\n *\n * \tExecute close syscall for given FD.\n *\n * Returns\n * \tA syscall result.\n */\nstatic long (*bpf_sys_close)(__u32 fd) = (void *) 168;\n\n/*\n * bpf_timer_init\n *\n * \tInitialize the timer.\n * \tFirst 4 bits of *flags* specify clockid.\n * \tOnly CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed.\n * \tAll other bits of *flags* are reserved.\n * \tThe verifier will reject the program if *timer* is not from\n * \tthe same *map*.\n *\n * Returns\n * \t0 on success.\n * \t**-EBUSY** if *timer* is already initialized.\n * \t**-EINVAL** if invalid *flags* are passed.\n * \t**-EPERM** if *timer* is in a map that doesn't have any user references.\n * \tThe user space should either hold a file descriptor to a map with timers\n * \tor pin such map in bpffs. When map is unpinned or file descriptor is\n * \tclosed all timers in the map will be cancelled and freed.\n */\nstatic long (*bpf_timer_init)(struct bpf_timer *timer, void *map, __u64 flags) = (void *) 169;\n\n/*\n * bpf_timer_set_callback\n *\n * \tConfigure the timer to call *callback_fn* static function.\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.\n * \t**-EPERM** if *timer* is in a map that doesn't have any user references.\n * \tThe user space should either hold a file descriptor to a map with timers\n * \tor pin such map in bpffs. When map is unpinned or file descriptor is\n * \tclosed all timers in the map will be cancelled and freed.\n */\nstatic long (*bpf_timer_set_callback)(struct bpf_timer *timer, void *callback_fn) = (void *) 170;\n\n/*\n * bpf_timer_start\n *\n * \tSet timer expiration N nanoseconds from the current time. The\n * \tconfigured callback will be invoked in soft irq context on some cpu\n * \tand will not repeat unless another bpf_timer_start() is made.\n * \tIn such case the next invocation can migrate to a different cpu.\n * \tSince struct bpf_timer is a field inside map element the map\n * \towns the timer. The bpf_timer_set_callback() will increment refcnt\n * \tof BPF program to make sure that callback_fn code stays valid.\n * \tWhen user space reference to a map reaches zero all timers\n * \tin a map are cancelled and corresponding program's refcnts are\n * \tdecremented. This is done to make sure that Ctrl-C of a user\n * \tprocess doesn't leave any timers running. If map is pinned in\n * \tbpffs the callback_fn can re-arm itself indefinitely.\n * \tbpf_map_update/delete_elem() helpers and user space sys_bpf commands\n * \tcancel and free the timer in the given map element.\n * \tThe map can contain timers that invoke callback_fn-s from different\n * \tprograms. The same callback_fn can serve different timers from\n * \tdifferent maps if key/value layout matches across maps.\n * \tEvery bpf_timer_set_callback() can have different callback_fn.\n *\n *\n * Returns\n * \t0 on success.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier\n * \tor invalid *flags* are passed.\n */\nstatic long (*bpf_timer_start)(struct bpf_timer *timer, __u64 nsecs, __u64 flags) = (void *) 171;\n\n/*\n * bpf_timer_cancel\n *\n * \tCancel the timer and wait for callback_fn to finish if it was running.\n *\n * Returns\n * \t0 if the timer was not active.\n * \t1 if the timer was active.\n * \t**-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.\n * \t**-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its\n * \town timer which would have led to a deadlock otherwise.\n */\nstatic long (*bpf_timer_cancel)(struct bpf_timer *timer) = (void *) 172;\n\n/*\n * bpf_get_func_ip\n *\n * \tGet address of the traced function (for tracing and kprobe programs).\n *\n * Returns\n * \tAddress of the traced function.\n */\nstatic __u64 (*bpf_get_func_ip)(void *ctx) = (void *) 173;\n\n/*\n * bpf_get_attach_cookie\n *\n * \tGet bpf_cookie value provided (optionally) during the program\n * \tattachment. It might be different for each individual\n * \tattachment, even if BPF program itself is the same.\n * \tExpects BPF program context *ctx* as a first argument.\n *\n * \tSupported for the following program types:\n * \t\t- kprobe/uprobe;\n * \t\t- tracepoint;\n * \t\t- perf_event.\n *\n * Returns\n * \tValue specified by user at BPF link creation/attachment time\n * \tor 0, if it was not specified.\n */\nstatic __u64 (*bpf_get_attach_cookie)(void *ctx) = (void *) 174;\n\n/*\n * bpf_task_pt_regs\n *\n * \tGet the struct pt_regs associated with **task**.\n *\n * Returns\n * \tA pointer to struct pt_regs.\n */\nstatic long (*bpf_task_pt_regs)(struct task_struct *task) = (void *) 175;\n\n\n"
  },
  {
    "path": "include/libbpf/bpf_helpers.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_HELPERS__\n#define __BPF_HELPERS__\n\n/*\n * Note that bpf programs need to include either\n * vmlinux.h (auto-generated from BTF) or linux/types.h\n * in advance since bpf_helper_defs.h uses such types\n * as __u64.\n */\n#include \"bpf_helper_defs.h\"\n\n#define __uint(name, val) int (*name)[val]\n#define __type(name, val) typeof(val) *name\n#define __array(name, val) typeof(val) *name[]\n\n/* Helper macro to print out debug messages */\n#define bpf_printk(fmt, ...)\t\t\t\t\\\n({\t\t\t\t\t\t\t\\\n\tchar ____fmt[] = fmt;\t\t\t\t\\\n\tbpf_trace_printk(____fmt, sizeof(____fmt),\t\\\n\t\t\t ##__VA_ARGS__);\t\t\\\n})\n\n/*\n * Helper macro to place programs, maps, license in\n * different sections in elf_bpf file. Section names\n * are interpreted by libbpf depending on the context (BPF programs, BPF maps,\n * extern variables, etc).\n * To allow use of SEC() with externs (e.g., for extern .maps declarations),\n * make sure __attribute__((unused)) doesn't trigger compilation warning.\n */\n#define SEC(name) \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wignored-attributes\\\"\")\t    \\\n\t__attribute__((section(name), used))\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n\n/* Avoid 'linux/stddef.h' definition of '__always_inline'. */\n#undef __always_inline\n#define __always_inline inline __attribute__((always_inline))\n\n#ifndef __noinline\n#define __noinline __attribute__((noinline))\n#endif\n#ifndef __weak\n#define __weak __attribute__((weak))\n#endif\n\n/*\n * Use __hidden attribute to mark a non-static BPF subprogram effectively\n * static for BPF verifier's verification algorithm purposes, allowing more\n * extensive and permissive BPF verification process, taking into account\n * subprogram's caller context.\n */\n#define __hidden __attribute__((visibility(\"hidden\")))\n\n/* When utilizing vmlinux.h with BPF CO-RE, user BPF programs can't include\n * any system-level headers (such as stddef.h, linux/version.h, etc), and\n * commonly-used macros like NULL and KERNEL_VERSION aren't available through\n * vmlinux.h. This just adds unnecessary hurdles and forces users to re-define\n * them on their own. So as a convenience, provide such definitions here.\n */\n#ifndef NULL\n#define NULL ((void *)0)\n#endif\n\n#ifndef KERNEL_VERSION\n#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))\n#endif\n\n/*\n * Helper macros to manipulate data structures\n */\n#ifndef offsetof\n#define offsetof(TYPE, MEMBER)\t((unsigned long)&((TYPE *)0)->MEMBER)\n#endif\n#ifndef container_of\n#define container_of(ptr, type, member)\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\\\n\t\tvoid *__mptr = (void *)(ptr);\t\t\t\\\n\t\t((type *)(__mptr - offsetof(type, member)));\t\\\n\t})\n#endif\n\n/*\n * Helper macro to throw a compilation error if __bpf_unreachable() gets\n * built into the resulting code. This works given BPF back end does not\n * implement __builtin_trap(). This is useful to assert that certain paths\n * of the program code are never used and hence eliminated by the compiler.\n *\n * For example, consider a switch statement that covers known cases used by\n * the program. __bpf_unreachable() can then reside in the default case. If\n * the program gets extended such that a case is not covered in the switch\n * statement, then it will throw a build error due to the default case not\n * being compiled out.\n */\n#ifndef __bpf_unreachable\n# define __bpf_unreachable()\t__builtin_trap()\n#endif\n\n/*\n * Helper function to perform a tail call with a constant/immediate map slot.\n */\n#if __clang_major__ >= 8 && defined(__bpf__)\nstatic __always_inline void\nbpf_tail_call_static(void *ctx, const void *map, const __u32 slot)\n{\n\tif (!__builtin_constant_p(slot))\n\t\t__bpf_unreachable();\n\n\t/*\n\t * Provide a hard guarantee that LLVM won't optimize setting r2 (map\n\t * pointer) and r3 (constant map index) from _different paths_ ending\n\t * up at the _same_ call insn as otherwise we won't be able to use the\n\t * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel\n\t * given they mismatch. See also d2e4c1e6c294 (\"bpf: Constant map key\n\t * tracking for prog array pokes\") for details on verifier tracking.\n\t *\n\t * Note on clobber list: we need to stay in-line with BPF calling\n\t * convention, so even if we don't end up using r0, r4, r5, we need\n\t * to mark them as clobber so that LLVM doesn't end up using them\n\t * before / after the call.\n\t */\n\tasm volatile(\"r1 = %[ctx]\\n\\t\"\n\t\t     \"r2 = %[map]\\n\\t\"\n\t\t     \"r3 = %[slot]\\n\\t\"\n\t\t     \"call 12\"\n\t\t     :: [ctx]\"r\"(ctx), [map]\"r\"(map), [slot]\"i\"(slot)\n\t\t     : \"r0\", \"r1\", \"r2\", \"r3\", \"r4\", \"r5\");\n}\n#endif\n\n/*\n * Helper structure used by eBPF C program\n * to describe BPF map attributes to libbpf loader\n */\nstruct bpf_map_def {\n\tunsigned int type;\n\tunsigned int key_size;\n\tunsigned int value_size;\n\tunsigned int max_entries;\n\tunsigned int map_flags;\n};\n\nenum libbpf_pin_type {\n\tLIBBPF_PIN_NONE,\n\t/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */\n\tLIBBPF_PIN_BY_NAME,\n};\n\nenum libbpf_tristate {\n\tTRI_NO = 0,\n\tTRI_YES = 1,\n\tTRI_MODULE = 2,\n};\n\n#define __kconfig __attribute__((section(\".kconfig\")))\n#define __ksym __attribute__((section(\".ksyms\")))\n\n#ifndef ___bpf_concat\n#define ___bpf_concat(a, b) a ## b\n#endif\n#ifndef ___bpf_apply\n#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)\n#endif\n#ifndef ___bpf_nth\n#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N\n#endif\n#ifndef ___bpf_narg\n#define ___bpf_narg(...) \\\n\t___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n#endif\n\n#define ___bpf_fill0(arr, p, x) do {} while (0)\n#define ___bpf_fill1(arr, p, x) arr[p] = x\n#define ___bpf_fill2(arr, p, x, args...) arr[p] = x; ___bpf_fill1(arr, p + 1, args)\n#define ___bpf_fill3(arr, p, x, args...) arr[p] = x; ___bpf_fill2(arr, p + 1, args)\n#define ___bpf_fill4(arr, p, x, args...) arr[p] = x; ___bpf_fill3(arr, p + 1, args)\n#define ___bpf_fill5(arr, p, x, args...) arr[p] = x; ___bpf_fill4(arr, p + 1, args)\n#define ___bpf_fill6(arr, p, x, args...) arr[p] = x; ___bpf_fill5(arr, p + 1, args)\n#define ___bpf_fill7(arr, p, x, args...) arr[p] = x; ___bpf_fill6(arr, p + 1, args)\n#define ___bpf_fill8(arr, p, x, args...) arr[p] = x; ___bpf_fill7(arr, p + 1, args)\n#define ___bpf_fill9(arr, p, x, args...) arr[p] = x; ___bpf_fill8(arr, p + 1, args)\n#define ___bpf_fill10(arr, p, x, args...) arr[p] = x; ___bpf_fill9(arr, p + 1, args)\n#define ___bpf_fill11(arr, p, x, args...) arr[p] = x; ___bpf_fill10(arr, p + 1, args)\n#define ___bpf_fill12(arr, p, x, args...) arr[p] = x; ___bpf_fill11(arr, p + 1, args)\n#define ___bpf_fill(arr, args...) \\\n\t___bpf_apply(___bpf_fill, ___bpf_narg(args))(arr, 0, args)\n\n/*\n * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values\n * in a structure.\n */\n#define BPF_SEQ_PRINTF(seq, fmt, args...)\t\t\t\\\n({\t\t\t\t\t\t\t\t\\\n\tstatic const char ___fmt[] = fmt;\t\t\t\\\n\tunsigned long long ___param[___bpf_narg(args)];\t\t\\\n\t\t\t\t\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\\\n\t___bpf_fill(___param, args);\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\\\n\t\t\t\t\t\t\t\t\\\n\tbpf_seq_printf(seq, ___fmt, sizeof(___fmt),\t\t\\\n\t\t       ___param, sizeof(___param));\t\t\\\n})\n\n/*\n * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of\n * an array of u64.\n */\n#define BPF_SNPRINTF(out, out_size, fmt, args...)\t\t\\\n({\t\t\t\t\t\t\t\t\\\n\tstatic const char ___fmt[] = fmt;\t\t\t\\\n\tunsigned long long ___param[___bpf_narg(args)];\t\t\\\n\t\t\t\t\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\\\n\t___bpf_fill(___param, args);\t\t\t\t\\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\\\n\t\t\t\t\t\t\t\t\\\n\tbpf_snprintf(out, out_size, ___fmt,\t\t\t\\\n\t\t     ___param, sizeof(___param));\t\t\\\n})\n\n#endif\n"
  },
  {
    "path": "include/libbpf/bpf_tracing.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n#ifndef __BPF_TRACING_H__\n#define __BPF_TRACING_H__\n\n/* Scan the ARCH passed in from ARCH env variable (see Makefile) */\n#if defined(__TARGET_ARCH_x86)\n\t#define bpf_target_x86\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_s390)\n\t#define bpf_target_s390\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_arm)\n\t#define bpf_target_arm\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_arm64)\n\t#define bpf_target_arm64\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_mips)\n\t#define bpf_target_mips\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_powerpc)\n\t#define bpf_target_powerpc\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_sparc)\n\t#define bpf_target_sparc\n\t#define bpf_target_defined\n#elif defined(__TARGET_ARCH_riscv)\n\t#define bpf_target_riscv\n\t#define bpf_target_defined\n#else\n\n/* Fall back to what the compiler says */\n#if defined(__x86_64__)\n\t#define bpf_target_x86\n\t#define bpf_target_defined\n#elif defined(__s390__)\n\t#define bpf_target_s390\n\t#define bpf_target_defined\n#elif defined(__arm__)\n\t#define bpf_target_arm\n\t#define bpf_target_defined\n#elif defined(__aarch64__)\n\t#define bpf_target_arm64\n\t#define bpf_target_defined\n#elif defined(__mips__)\n\t#define bpf_target_mips\n\t#define bpf_target_defined\n#elif defined(__powerpc__)\n\t#define bpf_target_powerpc\n\t#define bpf_target_defined\n#elif defined(__sparc__)\n\t#define bpf_target_sparc\n\t#define bpf_target_defined\n#elif defined(__riscv) && __riscv_xlen == 64\n\t#define bpf_target_riscv\n\t#define bpf_target_defined\n#endif /* no compiler target */\n\n#endif\n\n#ifndef __BPF_TARGET_MISSING\n#define __BPF_TARGET_MISSING \"GCC error \\\"Must specify a BPF target arch via __TARGET_ARCH_xxx\\\"\"\n#endif\n\n#if defined(bpf_target_x86)\n\n#if defined(__KERNEL__) || defined(__VMLINUX_H__)\n\n#define GO_PARAM1(x) ((x)->ax)\n#define GO_PARAM2(x) ((x)->bx)\n#define GO_PARAM3(x) ((x)->cx)\n#define GO_PARAM4(x) ((x)->di)\n#define GO_PARAM5(x) ((x)->si)\n#define GO_PARAM6(x) ((x)->r8)\n#define GO_PARAM7(x) ((x)->r9)\n#define GO_PARAM8(x) ((x)->r10)\n#define GO_PARAM9(x) ((x)->r11)\n#define GOROUTINE(x) ((x)->r14)\n\n#define PT_REGS_PARM1(x) ((x)->di)\n#define PT_REGS_PARM2(x) ((x)->si)\n#define PT_REGS_PARM3(x) ((x)->dx)\n#define PT_REGS_PARM4(x) ((x)->cx)\n#define PT_REGS_PARM5(x) ((x)->r8)\n#define PT_REGS_RET(x) ((x)->sp)\n#define PT_REGS_FP(x) ((x)->bp)\n#define PT_REGS_RC(x) ((x)->ax)\n#define PT_REGS_SP(x) ((x)->sp)\n#define PT_REGS_IP(x) ((x)->ip)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), di)\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), si)\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), dx)\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), cx)\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), sp)\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), bp)\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), ax)\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), ip)\n\n#else\n\n#ifdef __i386__\n/* i386 kernel is built with -mregparm=3 */\n#define PT_REGS_PARM1(x) ((x)->eax)\n#define PT_REGS_PARM2(x) ((x)->edx)\n#define PT_REGS_PARM3(x) ((x)->ecx)\n#define PT_REGS_PARM4(x) 0\n#define PT_REGS_PARM5(x) 0\n#define PT_REGS_RET(x) ((x)->esp)\n#define PT_REGS_FP(x) ((x)->ebp)\n#define PT_REGS_RC(x) ((x)->eax)\n#define PT_REGS_SP(x) ((x)->esp)\n#define PT_REGS_IP(x) ((x)->eip)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), eax)\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), edx)\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), ecx)\n#define PT_REGS_PARM4_CORE(x) 0\n#define PT_REGS_PARM5_CORE(x) 0\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), esp)\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), ebp)\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), eax)\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), esp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), eip)\n\n#else\n\n#define PT_REGS_PARM1(x) ((x)->rdi)\n#define PT_REGS_PARM2(x) ((x)->rsi)\n#define PT_REGS_PARM3(x) ((x)->rdx)\n#define PT_REGS_PARM4(x) ((x)->rcx)\n#define PT_REGS_PARM5(x) ((x)->r8)\n#define PT_REGS_RET(x) ((x)->rsp)\n#define PT_REGS_FP(x) ((x)->rbp)\n#define PT_REGS_RC(x) ((x)->rax)\n#define PT_REGS_SP(x) ((x)->rsp)\n#define PT_REGS_IP(x) ((x)->rip)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), rdi)\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), rsi)\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), rdx)\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), rcx)\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), r8)\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), rsp)\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), rbp)\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), rax)\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), rsp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), rip)\n\n#endif\n#endif\n\n#elif defined(bpf_target_s390)\n\n/* s390 provides user_pt_regs instead of struct pt_regs to userspace */\nstruct pt_regs;\n#define PT_REGS_S390 const volatile user_pt_regs\n#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2])\n#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3])\n#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4])\n#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5])\n#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6])\n#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14])\n/* Works only with CONFIG_FRAME_POINTER */\n#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11])\n#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2])\n#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15])\n#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[3])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[4])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[5])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[6])\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[14])\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[11])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[2])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), gprs[15])\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_S390 *)(x), psw.addr)\n\n#elif defined(bpf_target_arm)\n\n#define PT_REGS_PARM1(x) ((x)->uregs[0])\n#define PT_REGS_PARM2(x) ((x)->uregs[1])\n#define PT_REGS_PARM3(x) ((x)->uregs[2])\n#define PT_REGS_PARM4(x) ((x)->uregs[3])\n#define PT_REGS_PARM5(x) ((x)->uregs[4])\n#define PT_REGS_RET(x) ((x)->uregs[14])\n#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */\n#define PT_REGS_RC(x) ((x)->uregs[0])\n#define PT_REGS_SP(x) ((x)->uregs[13])\n#define PT_REGS_IP(x) ((x)->uregs[12])\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), uregs[0])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), uregs[1])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), uregs[2])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), uregs[3])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), uregs[4])\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), uregs[14])\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), uregs[11])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), uregs[0])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), uregs[13])\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), uregs[12])\n\n#elif defined(bpf_target_arm64)\n\n/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */\nstruct pt_regs;\n#define PT_REGS_ARM64 const volatile struct user_pt_regs\n\n#define GO_PARAM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])\n#define GO_PARAM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])\n#define GO_PARAM3(x) (((PT_REGS_ARM64 *)(x))->regs[2])\n#define GO_PARAM4(x) (((PT_REGS_ARM64 *)(x))->regs[3])\n#define GO_PARAM5(x) (((PT_REGS_ARM64 *)(x))->regs[4])\n#define GO_PARAM6(x) (((PT_REGS_ARM64 *)(x))->regs[5])\n#define GO_PARAM7(x) (((PT_REGS_ARM64 *)(x))->regs[6])\n#define GO_PARAM8(x) (((PT_REGS_ARM64 *)(x))->regs[7])\n#define GO_PARAM9(x) (((PT_REGS_ARM64 *)(x))->regs[8])\n#define GOROUTINE(x) (((PT_REGS_ARM64 *)(x))->regs[28])\n\n#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0])\n#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1])\n#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2])\n#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3])\n#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4])\n#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30])\n/* Works only with CONFIG_FRAME_POINTER */\n#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29])\n#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0])\n#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp)\n#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[1])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[2])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[3])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[4])\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[30])\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[29])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), regs[0])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), sp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_ARM64 *)(x), pc)\n\n#elif defined(bpf_target_mips)\n\n#define PT_REGS_PARM1(x) ((x)->regs[4])\n#define PT_REGS_PARM2(x) ((x)->regs[5])\n#define PT_REGS_PARM3(x) ((x)->regs[6])\n#define PT_REGS_PARM4(x) ((x)->regs[7])\n#define PT_REGS_PARM5(x) ((x)->regs[8])\n#define PT_REGS_RET(x) ((x)->regs[31])\n#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */\n#define PT_REGS_RC(x) ((x)->regs[2])\n#define PT_REGS_SP(x) ((x)->regs[29])\n#define PT_REGS_IP(x) ((x)->cp0_epc)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), regs[4])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), regs[5])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), regs[6])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), regs[7])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), regs[8])\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), regs[31])\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((x), regs[30])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), regs[2])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), regs[29])\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), cp0_epc)\n\n#elif defined(bpf_target_powerpc)\n\n#define PT_REGS_PARM1(x) ((x)->gpr[3])\n#define PT_REGS_PARM2(x) ((x)->gpr[4])\n#define PT_REGS_PARM3(x) ((x)->gpr[5])\n#define PT_REGS_PARM4(x) ((x)->gpr[6])\n#define PT_REGS_PARM5(x) ((x)->gpr[7])\n#define PT_REGS_RC(x) ((x)->gpr[3])\n#define PT_REGS_SP(x) ((x)->sp)\n#define PT_REGS_IP(x) ((x)->nip)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), gpr[3])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), gpr[4])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), gpr[5])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), gpr[6])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), gpr[7])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), gpr[3])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), sp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), nip)\n\n#elif defined(bpf_target_sparc)\n\n#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])\n#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1])\n#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2])\n#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3])\n#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4])\n#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7])\n#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])\n#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I1])\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I2])\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I3])\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I4])\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I7])\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((x), u_regs[UREG_I0])\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((x), u_regs[UREG_FP])\n\n/* Should this also be a bpf_target check for the sparc case? */\n#if defined(__arch64__)\n#define PT_REGS_IP(x) ((x)->tpc)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), tpc)\n#else\n#define PT_REGS_IP(x) ((x)->pc)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((x), pc)\n#endif\n\n#elif defined(bpf_target_riscv)\n\nstruct pt_regs;\n#define PT_REGS_RV const volatile struct user_regs_struct\n#define PT_REGS_PARM1(x) (((PT_REGS_RV *)(x))->a0)\n#define PT_REGS_PARM2(x) (((PT_REGS_RV *)(x))->a1)\n#define PT_REGS_PARM3(x) (((PT_REGS_RV *)(x))->a2)\n#define PT_REGS_PARM4(x) (((PT_REGS_RV *)(x))->a3)\n#define PT_REGS_PARM5(x) (((PT_REGS_RV *)(x))->a4)\n#define PT_REGS_RET(x) (((PT_REGS_RV *)(x))->ra)\n#define PT_REGS_FP(x) (((PT_REGS_RV *)(x))->s5)\n#define PT_REGS_RC(x) (((PT_REGS_RV *)(x))->a5)\n#define PT_REGS_SP(x) (((PT_REGS_RV *)(x))->sp)\n#define PT_REGS_IP(x) (((PT_REGS_RV *)(x))->epc)\n\n#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a0)\n#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a1)\n#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a2)\n#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a3)\n#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a4)\n#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), ra)\n#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), fp)\n#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), a5)\n#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), sp)\n#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_RV *)(x), epc)\n\n#endif\n\n#if defined(bpf_target_powerpc)\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t({ (ip) = (ctx)->link; })\n#define BPF_KRETPROBE_READ_RET_IP\t\tBPF_KPROBE_READ_RET_IP\n#elif defined(bpf_target_sparc)\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t({ (ip) = PT_REGS_RET(ctx); })\n#define BPF_KRETPROBE_READ_RET_IP\t\tBPF_KPROBE_READ_RET_IP\n#elif defined(bpf_target_defined)\n#define BPF_KPROBE_READ_RET_IP(ip, ctx)\t\t\t\t\t    \\\n\t({ bpf_probe_read_kernel(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })\n#define BPF_KRETPROBE_READ_RET_IP(ip, ctx)\t\t\t\t    \\\n\t({ bpf_probe_read_kernel(&(ip), sizeof(ip),\t\t\t    \\\n\t\t\t  (void *)(PT_REGS_FP(ctx) + sizeof(ip))); })\n#endif\n\n#if !defined(bpf_target_defined)\n\n#define PT_REGS_PARM1(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RET(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_FP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RC(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_SP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_IP(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define PT_REGS_PARM1_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM2_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM3_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM4_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_PARM5_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RET_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_FP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_RC_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_SP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define PT_REGS_IP_CORE(x) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ _Pragma(__BPF_TARGET_MISSING); 0l; })\n\n#endif /* !defined(bpf_target_defined) */\n\n#ifndef ___bpf_concat\n#define ___bpf_concat(a, b) a ## b\n#endif\n#ifndef ___bpf_apply\n#define ___bpf_apply(fn, n) ___bpf_concat(fn, n)\n#endif\n#ifndef ___bpf_nth\n#define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N\n#endif\n#ifndef ___bpf_narg\n#define ___bpf_narg(...) \\\n\t___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)\n#endif\n\n#define ___bpf_ctx_cast0() ctx\n#define ___bpf_ctx_cast1(x) ___bpf_ctx_cast0(), (void *)ctx[0]\n#define ___bpf_ctx_cast2(x, args...) ___bpf_ctx_cast1(args), (void *)ctx[1]\n#define ___bpf_ctx_cast3(x, args...) ___bpf_ctx_cast2(args), (void *)ctx[2]\n#define ___bpf_ctx_cast4(x, args...) ___bpf_ctx_cast3(args), (void *)ctx[3]\n#define ___bpf_ctx_cast5(x, args...) ___bpf_ctx_cast4(args), (void *)ctx[4]\n#define ___bpf_ctx_cast6(x, args...) ___bpf_ctx_cast5(args), (void *)ctx[5]\n#define ___bpf_ctx_cast7(x, args...) ___bpf_ctx_cast6(args), (void *)ctx[6]\n#define ___bpf_ctx_cast8(x, args...) ___bpf_ctx_cast7(args), (void *)ctx[7]\n#define ___bpf_ctx_cast9(x, args...) ___bpf_ctx_cast8(args), (void *)ctx[8]\n#define ___bpf_ctx_cast10(x, args...) ___bpf_ctx_cast9(args), (void *)ctx[9]\n#define ___bpf_ctx_cast11(x, args...) ___bpf_ctx_cast10(args), (void *)ctx[10]\n#define ___bpf_ctx_cast12(x, args...) ___bpf_ctx_cast11(args), (void *)ctx[11]\n#define ___bpf_ctx_cast(args...) \\\n\t___bpf_apply(___bpf_ctx_cast, ___bpf_narg(args))(args)\n\n/*\n * BPF_PROG is a convenience wrapper for generic tp_btf/fentry/fexit and\n * similar kinds of BPF programs, that accept input arguments as a single\n * pointer to untyped u64 array, where each u64 can actually be a typed\n * pointer or integer of different size. Instead of requring user to write\n * manual casts and work with array elements by index, BPF_PROG macro\n * allows user to declare a list of named and typed input arguments in the\n * same syntax as for normal C function. All the casting is hidden and\n * performed transparently, while user code can just assume working with\n * function arguments of specified type and name.\n *\n * Original raw context argument is preserved as well as 'ctx' argument.\n * This is useful when using BPF helpers that expect original context\n * as one of the parameters (e.g., for bpf_perf_event_output()).\n */\n#define BPF_PROG(name, args...)\t\t\t\t\t\t    \\\nname(unsigned long long *ctx);\t\t\t\t\t\t    \\\nstatic __attribute__((always_inline)) typeof(name(0))\t\t\t    \\\n____##name(unsigned long long *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(unsigned long long *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_ctx_cast(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __attribute__((always_inline)) typeof(name(0))\t\t\t    \\\n____##name(unsigned long long *ctx, ##args)\n\nstruct pt_regs;\n\n#define ___bpf_kprobe_args0() ctx\n#define ___bpf_kprobe_args1(x) \\\n\t___bpf_kprobe_args0(), (void *)PT_REGS_PARM1(ctx)\n#define ___bpf_kprobe_args2(x, args...) \\\n\t___bpf_kprobe_args1(args), (void *)PT_REGS_PARM2(ctx)\n#define ___bpf_kprobe_args3(x, args...) \\\n\t___bpf_kprobe_args2(args), (void *)PT_REGS_PARM3(ctx)\n#define ___bpf_kprobe_args4(x, args...) \\\n\t___bpf_kprobe_args3(args), (void *)PT_REGS_PARM4(ctx)\n#define ___bpf_kprobe_args5(x, args...) \\\n\t___bpf_kprobe_args4(args), (void *)PT_REGS_PARM5(ctx)\n#define ___bpf_kprobe_args(args...) \\\n\t___bpf_apply(___bpf_kprobe_args, ___bpf_narg(args))(args)\n\n/*\n * BPF_KPROBE serves the same purpose for kprobes as BPF_PROG for\n * tp_btf/fentry/fexit BPF programs. It hides the underlying platform-specific\n * low-level way of getting kprobe input arguments from struct pt_regs, and\n * provides a familiar typed and named function arguments syntax and\n * semantics of accessing kprobe input paremeters.\n *\n * Original struct pt_regs* context is preserved as 'ctx' argument. This might\n * be necessary when using BPF helpers like bpf_perf_event_output().\n */\n#define BPF_KPROBE(name, args...)\t\t\t\t\t    \\\nname(struct pt_regs *ctx);\t\t\t\t\t\t    \\\nstatic __attribute__((always_inline)) typeof(name(0))\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(struct pt_regs *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_kprobe_args(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __attribute__((always_inline)) typeof(name(0))\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args)\n\n#define ___bpf_kretprobe_args0() ctx\n#define ___bpf_kretprobe_args1(x) \\\n\t___bpf_kretprobe_args0(), (void *)PT_REGS_RC(ctx)\n#define ___bpf_kretprobe_args(args...) \\\n\t___bpf_apply(___bpf_kretprobe_args, ___bpf_narg(args))(args)\n\n/*\n * BPF_KRETPROBE is similar to BPF_KPROBE, except, it only provides optional\n * return value (in addition to `struct pt_regs *ctx`), but no input\n * arguments, because they will be clobbered by the time probed function\n * returns.\n */\n#define BPF_KRETPROBE(name, args...)\t\t\t\t\t    \\\nname(struct pt_regs *ctx);\t\t\t\t\t\t    \\\nstatic __attribute__((always_inline)) typeof(name(0))\t\t\t    \\\n____##name(struct pt_regs *ctx, ##args);\t\t\t\t    \\\ntypeof(name(0)) name(struct pt_regs *ctx)\t\t\t\t    \\\n{\t\t\t\t\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic push\")\t\t\t\t\t    \\\n\t_Pragma(\"GCC diagnostic ignored \\\"-Wint-conversion\\\"\")\t\t    \\\n\treturn ____##name(___bpf_kretprobe_args(args));\t\t\t    \\\n\t_Pragma(\"GCC diagnostic pop\")\t\t\t\t\t    \\\n}\t\t\t\t\t\t\t\t\t    \\\nstatic __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args)\n\n#endif\n"
  },
  {
    "path": "include/libbpf/btf.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n/* Copyright (c) 2018 Facebook */\n\n#ifndef __LIBBPF_BTF_H\n#define __LIBBPF_BTF_H\n\n#include <stdarg.h>\n#include <stdbool.h>\n#include <linux/btf.h>\n#include <linux/types.h>\n\n#include \"libbpf_common.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define BTF_ELF_SEC \".BTF\"\n#define BTF_EXT_ELF_SEC \".BTF.ext\"\n#define MAPS_ELF_SEC \".maps\"\n\nstruct btf;\nstruct btf_ext;\nstruct btf_type;\n\nstruct bpf_object;\n\nenum btf_endianness {\n\tBTF_LITTLE_ENDIAN = 0,\n\tBTF_BIG_ENDIAN = 1,\n};\n\nLIBBPF_API void btf__free(struct btf *btf);\n\nLIBBPF_API struct btf *btf__new(const void *data, __u32 size);\nLIBBPF_API struct btf *btf__new_split(const void *data, __u32 size, struct btf *base_btf);\nLIBBPF_API struct btf *btf__new_empty(void);\nLIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf);\n\nLIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext);\nLIBBPF_API struct btf *btf__parse_split(const char *path, struct btf *base_btf);\nLIBBPF_API struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext);\nLIBBPF_API struct btf *btf__parse_elf_split(const char *path, struct btf *base_btf);\nLIBBPF_API struct btf *btf__parse_raw(const char *path);\nLIBBPF_API struct btf *btf__parse_raw_split(const char *path, struct btf *base_btf);\n\nLIBBPF_API struct btf *btf__load_vmlinux_btf(void);\nLIBBPF_API struct btf *btf__load_module_btf(const char *module_name, struct btf *vmlinux_btf);\nLIBBPF_API struct btf *libbpf_find_kernel_btf(void);\n\nLIBBPF_API struct btf *btf__load_from_kernel_by_id(__u32 id);\nLIBBPF_API struct btf *btf__load_from_kernel_by_id_split(__u32 id, struct btf *base_btf);\nLIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);\n\nLIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);\nLIBBPF_API int btf__load(struct btf *btf);\nLIBBPF_API int btf__load_into_kernel(struct btf *btf);\nLIBBPF_API __s32 btf__find_by_name(const struct btf *btf,\n\t\t\t\t   const char *type_name);\nLIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,\n\t\t\t\t\tconst char *type_name, __u32 kind);\nLIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);\nLIBBPF_API const struct btf *btf__base_btf(const struct btf *btf);\nLIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,\n\t\t\t\t\t\t  __u32 id);\nLIBBPF_API size_t btf__pointer_size(const struct btf *btf);\nLIBBPF_API int btf__set_pointer_size(struct btf *btf, size_t ptr_sz);\nLIBBPF_API enum btf_endianness btf__endianness(const struct btf *btf);\nLIBBPF_API int btf__set_endianness(struct btf *btf, enum btf_endianness endian);\nLIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);\nLIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);\nLIBBPF_API int btf__align_of(const struct btf *btf, __u32 id);\nLIBBPF_API int btf__fd(const struct btf *btf);\nLIBBPF_API void btf__set_fd(struct btf *btf, int fd);\nLIBBPF_API const void *btf__get_raw_data(const struct btf *btf, __u32 *size);\nLIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);\nLIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset);\nLIBBPF_API int btf__get_map_kv_tids(const struct btf *btf, const char *map_name,\n\t\t\t\t    __u32 expected_key_size,\n\t\t\t\t    __u32 expected_value_size,\n\t\t\t\t    __u32 *key_type_id, __u32 *value_type_id);\n\nLIBBPF_API struct btf_ext *btf_ext__new(__u8 *data, __u32 size);\nLIBBPF_API void btf_ext__free(struct btf_ext *btf_ext);\nLIBBPF_API const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext,\n\t\t\t\t\t     __u32 *size);\nLIBBPF_API LIBBPF_DEPRECATED(\"btf_ext__reloc_func_info was never meant as a public API and has wrong assumptions embedded in it; it will be removed in the future libbpf versions\")\nint btf_ext__reloc_func_info(const struct btf *btf,\n\t\t\t     const struct btf_ext *btf_ext,\n\t\t\t     const char *sec_name, __u32 insns_cnt,\n\t\t\t     void **func_info, __u32 *cnt);\nLIBBPF_API LIBBPF_DEPRECATED(\"btf_ext__reloc_line_info was never meant as a public API and has wrong assumptions embedded in it; it will be removed in the future libbpf versions\")\nint btf_ext__reloc_line_info(const struct btf *btf,\n\t\t\t     const struct btf_ext *btf_ext,\n\t\t\t     const char *sec_name, __u32 insns_cnt,\n\t\t\t     void **line_info, __u32 *cnt);\nLIBBPF_API __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);\nLIBBPF_API __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);\n\nLIBBPF_API int btf__find_str(struct btf *btf, const char *s);\nLIBBPF_API int btf__add_str(struct btf *btf, const char *s);\nLIBBPF_API int btf__add_type(struct btf *btf, const struct btf *src_btf,\n\t\t\t     const struct btf_type *src_type);\n\nLIBBPF_API int btf__add_int(struct btf *btf, const char *name, size_t byte_sz, int encoding);\nLIBBPF_API int btf__add_float(struct btf *btf, const char *name, size_t byte_sz);\nLIBBPF_API int btf__add_ptr(struct btf *btf, int ref_type_id);\nLIBBPF_API int btf__add_array(struct btf *btf,\n\t\t\t      int index_type_id, int elem_type_id, __u32 nr_elems);\n/* struct/union construction APIs */\nLIBBPF_API int btf__add_struct(struct btf *btf, const char *name, __u32 sz);\nLIBBPF_API int btf__add_union(struct btf *btf, const char *name, __u32 sz);\nLIBBPF_API int btf__add_field(struct btf *btf, const char *name, int field_type_id,\n\t\t\t      __u32 bit_offset, __u32 bit_size);\n\n/* enum construction APIs */\nLIBBPF_API int btf__add_enum(struct btf *btf, const char *name, __u32 bytes_sz);\nLIBBPF_API int btf__add_enum_value(struct btf *btf, const char *name, __s64 value);\n\nenum btf_fwd_kind {\n\tBTF_FWD_STRUCT = 0,\n\tBTF_FWD_UNION = 1,\n\tBTF_FWD_ENUM = 2,\n};\n\nLIBBPF_API int btf__add_fwd(struct btf *btf, const char *name, enum btf_fwd_kind fwd_kind);\nLIBBPF_API int btf__add_typedef(struct btf *btf, const char *name, int ref_type_id);\nLIBBPF_API int btf__add_volatile(struct btf *btf, int ref_type_id);\nLIBBPF_API int btf__add_const(struct btf *btf, int ref_type_id);\nLIBBPF_API int btf__add_restrict(struct btf *btf, int ref_type_id);\n\n/* func and func_proto construction APIs */\nLIBBPF_API int btf__add_func(struct btf *btf, const char *name,\n\t\t\t     enum btf_func_linkage linkage, int proto_type_id);\nLIBBPF_API int btf__add_func_proto(struct btf *btf, int ret_type_id);\nLIBBPF_API int btf__add_func_param(struct btf *btf, const char *name, int type_id);\n\n/* var & datasec construction APIs */\nLIBBPF_API int btf__add_var(struct btf *btf, const char *name, int linkage, int type_id);\nLIBBPF_API int btf__add_datasec(struct btf *btf, const char *name, __u32 byte_sz);\nLIBBPF_API int btf__add_datasec_var_info(struct btf *btf, int var_type_id,\n\t\t\t\t\t __u32 offset, __u32 byte_sz);\n\nstruct btf_dedup_opts {\n\tunsigned int dedup_table_size;\n\tbool dont_resolve_fwds;\n};\n\nLIBBPF_API int btf__dedup(struct btf *btf, struct btf_ext *btf_ext,\n\t\t\t  const struct btf_dedup_opts *opts);\n\nstruct btf_dump;\n\nstruct btf_dump_opts {\n\tvoid *ctx;\n};\n\ntypedef void (*btf_dump_printf_fn_t)(void *ctx, const char *fmt, va_list args);\n\nLIBBPF_API struct btf_dump *btf_dump__new(const struct btf *btf,\n\t\t\t\t\t  const struct btf_ext *btf_ext,\n\t\t\t\t\t  const struct btf_dump_opts *opts,\n\t\t\t\t\t  btf_dump_printf_fn_t printf_fn);\nLIBBPF_API void btf_dump__free(struct btf_dump *d);\n\nLIBBPF_API int btf_dump__dump_type(struct btf_dump *d, __u32 id);\n\nstruct btf_dump_emit_type_decl_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* optional field name for type declaration, e.g.:\n\t * - struct my_struct <FNAME>\n\t * - void (*<FNAME>)(int)\n\t * - char (*<FNAME>)[123]\n\t */\n\tconst char *field_name;\n\t/* extra indentation level (in number of tabs) to emit for multi-line\n\t * type declarations (e.g., anonymous struct); applies for lines\n\t * starting from the second one (first line is assumed to have\n\t * necessary indentation already\n\t */\n\tint indent_level;\n\t/* strip all the const/volatile/restrict mods */\n\tbool strip_mods;\n\tsize_t :0;\n};\n#define btf_dump_emit_type_decl_opts__last_field strip_mods\n\nLIBBPF_API int\nbtf_dump__emit_type_decl(struct btf_dump *d, __u32 id,\n\t\t\t const struct btf_dump_emit_type_decl_opts *opts);\n\n\nstruct btf_dump_type_data_opts {\n\t/* size of this struct, for forward/backward compatibility */\n\tsize_t sz;\n\tconst char *indent_str;\n\tint indent_level;\n\t/* below match \"show\" flags for bpf_show_snprintf() */\n\tbool compact;\t\t/* no newlines/indentation */\n\tbool skip_names;\t/* skip member/type names */\n\tbool emit_zeroes;\t/* show 0-valued fields */\n\tsize_t :0;\n};\n#define btf_dump_type_data_opts__last_field emit_zeroes\n\nLIBBPF_API int\nbtf_dump__dump_type_data(struct btf_dump *d, __u32 id,\n\t\t\t const void *data, size_t data_sz,\n\t\t\t const struct btf_dump_type_data_opts *opts);\n\n/*\n * A set of helpers for easier BTF types handling\n */\nstatic inline __u16 btf_kind(const struct btf_type *t)\n{\n\treturn BTF_INFO_KIND(t->info);\n}\n\nstatic inline __u16 btf_vlen(const struct btf_type *t)\n{\n\treturn BTF_INFO_VLEN(t->info);\n}\n\nstatic inline bool btf_kflag(const struct btf_type *t)\n{\n\treturn BTF_INFO_KFLAG(t->info);\n}\n\nstatic inline bool btf_is_void(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_UNKN;\n}\n\nstatic inline bool btf_is_int(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_INT;\n}\n\nstatic inline bool btf_is_ptr(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_PTR;\n}\n\nstatic inline bool btf_is_array(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_ARRAY;\n}\n\nstatic inline bool btf_is_struct(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_STRUCT;\n}\n\nstatic inline bool btf_is_union(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_UNION;\n}\n\nstatic inline bool btf_is_composite(const struct btf_type *t)\n{\n\t__u16 kind = btf_kind(t);\n\n\treturn kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;\n}\n\nstatic inline bool btf_is_enum(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_ENUM;\n}\n\nstatic inline bool btf_is_fwd(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_FWD;\n}\n\nstatic inline bool btf_is_typedef(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_TYPEDEF;\n}\n\nstatic inline bool btf_is_volatile(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_VOLATILE;\n}\n\nstatic inline bool btf_is_const(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_CONST;\n}\n\nstatic inline bool btf_is_restrict(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_RESTRICT;\n}\n\nstatic inline bool btf_is_mod(const struct btf_type *t)\n{\n\t__u16 kind = btf_kind(t);\n\n\treturn kind == BTF_KIND_VOLATILE ||\n\t       kind == BTF_KIND_CONST ||\n\t       kind == BTF_KIND_RESTRICT;\n}\n\nstatic inline bool btf_is_func(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_FUNC;\n}\n\nstatic inline bool btf_is_func_proto(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_FUNC_PROTO;\n}\n\nstatic inline bool btf_is_var(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_VAR;\n}\n\nstatic inline bool btf_is_datasec(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_DATASEC;\n}\n\nstatic inline bool btf_is_float(const struct btf_type *t)\n{\n\treturn btf_kind(t) == BTF_KIND_FLOAT;\n}\n\nstatic inline __u8 btf_int_encoding(const struct btf_type *t)\n{\n\treturn BTF_INT_ENCODING(*(__u32 *)(t + 1));\n}\n\nstatic inline __u8 btf_int_offset(const struct btf_type *t)\n{\n\treturn BTF_INT_OFFSET(*(__u32 *)(t + 1));\n}\n\nstatic inline __u8 btf_int_bits(const struct btf_type *t)\n{\n\treturn BTF_INT_BITS(*(__u32 *)(t + 1));\n}\n\nstatic inline struct btf_array *btf_array(const struct btf_type *t)\n{\n\treturn (struct btf_array *)(t + 1);\n}\n\nstatic inline struct btf_enum *btf_enum(const struct btf_type *t)\n{\n\treturn (struct btf_enum *)(t + 1);\n}\n\nstatic inline struct btf_member *btf_members(const struct btf_type *t)\n{\n\treturn (struct btf_member *)(t + 1);\n}\n\n/* Get bit offset of a member with specified index. */\nstatic inline __u32 btf_member_bit_offset(const struct btf_type *t,\n\t\t\t\t\t  __u32 member_idx)\n{\n\tconst struct btf_member *m = btf_members(t) + member_idx;\n\tbool kflag = btf_kflag(t);\n\n\treturn kflag ? BTF_MEMBER_BIT_OFFSET(m->offset) : m->offset;\n}\n/*\n * Get bitfield size of a member, assuming t is BTF_KIND_STRUCT or\n * BTF_KIND_UNION. If member is not a bitfield, zero is returned.\n */\nstatic inline __u32 btf_member_bitfield_size(const struct btf_type *t,\n\t\t\t\t\t     __u32 member_idx)\n{\n\tconst struct btf_member *m = btf_members(t) + member_idx;\n\tbool kflag = btf_kflag(t);\n\n\treturn kflag ? BTF_MEMBER_BITFIELD_SIZE(m->offset) : 0;\n}\n\nstatic inline struct btf_param *btf_params(const struct btf_type *t)\n{\n\treturn (struct btf_param *)(t + 1);\n}\n\nstatic inline struct btf_var *btf_var(const struct btf_type *t)\n{\n\treturn (struct btf_var *)(t + 1);\n}\n\nstatic inline struct btf_var_secinfo *\nbtf_var_secinfos(const struct btf_type *t)\n{\n\treturn (struct btf_var_secinfo *)(t + 1);\n}\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* __LIBBPF_BTF_H */\n"
  },
  {
    "path": "include/libbpf/libbpf.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n\n/*\n * Common eBPF ELF object loading operations.\n *\n * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>\n * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>\n * Copyright (C) 2015 Huawei Inc.\n */\n#ifndef __LIBBPF_LIBBPF_H\n#define __LIBBPF_LIBBPF_H\n\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <sys/types.h>  // for size_t\n#include <linux/bpf.h>\n\n#include \"libbpf_common.h\"\n#include \"libbpf_legacy.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum libbpf_errno {\n\t__LIBBPF_ERRNO__START = 4000,\n\n\t/* Something wrong in libelf */\n\tLIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,\n\tLIBBPF_ERRNO__FORMAT,\t/* BPF object format invalid */\n\tLIBBPF_ERRNO__KVERSION,\t/* Incorrect or no 'version' section */\n\tLIBBPF_ERRNO__ENDIAN,\t/* Endian mismatch */\n\tLIBBPF_ERRNO__INTERNAL,\t/* Internal error in libbpf */\n\tLIBBPF_ERRNO__RELOC,\t/* Relocation failed */\n\tLIBBPF_ERRNO__LOAD,\t/* Load program failure for unknown reason */\n\tLIBBPF_ERRNO__VERIFY,\t/* Kernel verifier blocks program loading */\n\tLIBBPF_ERRNO__PROG2BIG,\t/* Program too big */\n\tLIBBPF_ERRNO__KVER,\t/* Incorrect kernel version */\n\tLIBBPF_ERRNO__PROGTYPE,\t/* Kernel doesn't support this program type */\n\tLIBBPF_ERRNO__WRNGPID,\t/* Wrong pid in netlink message */\n\tLIBBPF_ERRNO__INVSEQ,\t/* Invalid netlink sequence */\n\tLIBBPF_ERRNO__NLPARSE,\t/* netlink parsing error */\n\t__LIBBPF_ERRNO__END,\n};\n\nLIBBPF_API int libbpf_strerror(int err, char *buf, size_t size);\n\nenum libbpf_print_level {\n        LIBBPF_WARN,\n        LIBBPF_INFO,\n        LIBBPF_DEBUG,\n};\n\ntypedef int (*libbpf_print_fn_t)(enum libbpf_print_level level,\n\t\t\t\t const char *, va_list ap);\n\nLIBBPF_API libbpf_print_fn_t libbpf_set_print(libbpf_print_fn_t fn);\n\n/* Hide internal to user */\nstruct bpf_object;\n\nstruct bpf_object_open_attr {\n\tconst char *file;\n\tenum bpf_prog_type prog_type;\n};\n\nstruct bpf_object_open_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* object name override, if provided:\n\t * - for object open from file, this will override setting object\n\t *   name from file path's base name;\n\t * - for object open from memory buffer, this will specify an object\n\t *   name and will override default \"<addr>-<buf-size>\" name;\n\t */\n\tconst char *object_name;\n\t/* parse map definitions non-strictly, allowing extra attributes/data */\n\tbool relaxed_maps;\n\t/* DEPRECATED: handle CO-RE relocations non-strictly, allowing failures.\n\t * Value is ignored. Relocations always are processed non-strictly.\n\t * Non-relocatable instructions are replaced with invalid ones to\n\t * prevent accidental errors.\n\t * */\n\tbool relaxed_core_relocs;\n\t/* maps that set the 'pinning' attribute in their definition will have\n\t * their pin_path attribute set to a file in this directory, and be\n\t * auto-pinned to that path on load; defaults to \"/sys/fs/bpf\".\n\t */\n\tconst char *pin_root_path;\n\t__u32 attach_prog_fd;\n\t/* Additional kernel config content that augments and overrides\n\t * system Kconfig for CONFIG_xxx externs.\n\t */\n\tconst char *kconfig;\n\t/* Path to the custom BTF to be used for BPF CO-RE relocations.\n\t * This custom BTF completely replaces the use of vmlinux BTF\n\t * for the purpose of CO-RE relocations.\n\t * NOTE: any other BPF feature (e.g., fentry/fexit programs,\n\t * struct_ops, etc) will need actual kernel BTF at /sys/kernel/btf/vmlinux.\n\t */\n\tconst char *btf_custom_path;\n};\n#define bpf_object_open_opts__last_field btf_custom_path\n\nLIBBPF_API struct bpf_object *bpf_object__open(const char *path);\nLIBBPF_API struct bpf_object *\nbpf_object__open_file(const char *path, const struct bpf_object_open_opts *opts);\nLIBBPF_API struct bpf_object *\nbpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,\n\t\t     const struct bpf_object_open_opts *opts);\n\n/* deprecated bpf_object__open variants */\nLIBBPF_API struct bpf_object *\nbpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz,\n\t\t\tconst char *name);\nLIBBPF_API struct bpf_object *\nbpf_object__open_xattr(struct bpf_object_open_attr *attr);\n\nenum libbpf_pin_type {\n\tLIBBPF_PIN_NONE,\n\t/* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */\n\tLIBBPF_PIN_BY_NAME,\n};\n\n/* pin_maps and unpin_maps can both be called with a NULL path, in which case\n * they will use the pin_path attribute of each map (and ignore all maps that\n * don't have a pin_path set).\n */\nLIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);\nLIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,\n\t\t\t\t      const char *path);\nLIBBPF_API int bpf_object__pin_programs(struct bpf_object *obj,\n\t\t\t\t\tconst char *path);\nLIBBPF_API int bpf_object__unpin_programs(struct bpf_object *obj,\n\t\t\t\t\t  const char *path);\nLIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);\nLIBBPF_API void bpf_object__close(struct bpf_object *object);\n\nstruct bpf_object_load_attr {\n\tstruct bpf_object *obj;\n\tint log_level;\n\tconst char *target_btf_path;\n};\n\n/* Load/unload object into/from kernel */\nLIBBPF_API int bpf_object__load(struct bpf_object *obj);\nLIBBPF_API int bpf_object__load_xattr(struct bpf_object_load_attr *attr);\nLIBBPF_API int bpf_object__unload(struct bpf_object *obj);\n\nLIBBPF_API const char *bpf_object__name(const struct bpf_object *obj);\nLIBBPF_API unsigned int bpf_object__kversion(const struct bpf_object *obj);\nLIBBPF_API int bpf_object__set_kversion(struct bpf_object *obj, __u32 kern_version);\n\nstruct btf;\nLIBBPF_API struct btf *bpf_object__btf(const struct bpf_object *obj);\nLIBBPF_API int bpf_object__btf_fd(const struct bpf_object *obj);\n\nLIBBPF_API struct bpf_program *\nbpf_object__find_program_by_title(const struct bpf_object *obj,\n\t\t\t\t  const char *title);\nLIBBPF_API struct bpf_program *\nbpf_object__find_program_by_name(const struct bpf_object *obj,\n\t\t\t\t const char *name);\n\nLIBBPF_API struct bpf_object *bpf_object__next(struct bpf_object *prev);\n#define bpf_object__for_each_safe(pos, tmp)\t\t\t\\\n\tfor ((pos) = bpf_object__next(NULL),\t\t\\\n\t\t(tmp) = bpf_object__next(pos);\t\t\\\n\t     (pos) != NULL;\t\t\t\t\\\n\t     (pos) = (tmp), (tmp) = bpf_object__next(tmp))\n\ntypedef void (*bpf_object_clear_priv_t)(struct bpf_object *, void *);\nLIBBPF_API int bpf_object__set_priv(struct bpf_object *obj, void *priv,\n\t\t\t\t    bpf_object_clear_priv_t clear_priv);\nLIBBPF_API void *bpf_object__priv(const struct bpf_object *prog);\n\nLIBBPF_API int\nlibbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,\n\t\t\t enum bpf_attach_type *expected_attach_type);\nLIBBPF_API int libbpf_attach_type_by_name(const char *name,\n\t\t\t\t\t  enum bpf_attach_type *attach_type);\nLIBBPF_API int libbpf_find_vmlinux_btf_id(const char *name,\n\t\t\t\t\t  enum bpf_attach_type attach_type);\n\n/* Accessors of bpf_program */\nstruct bpf_program;\nLIBBPF_API struct bpf_program *bpf_program__next(struct bpf_program *prog,\n\t\t\t\t\t\t const struct bpf_object *obj);\n\n#define bpf_object__for_each_program(pos, obj)\t\t\\\n\tfor ((pos) = bpf_program__next(NULL, (obj));\t\\\n\t     (pos) != NULL;\t\t\t\t\\\n\t     (pos) = bpf_program__next((pos), (obj)))\n\nLIBBPF_API struct bpf_program *bpf_program__prev(struct bpf_program *prog,\n\t\t\t\t\t\t const struct bpf_object *obj);\n\ntypedef void (*bpf_program_clear_priv_t)(struct bpf_program *, void *);\n\nLIBBPF_API int bpf_program__set_priv(struct bpf_program *prog, void *priv,\n\t\t\t\t     bpf_program_clear_priv_t clear_priv);\n\nLIBBPF_API void *bpf_program__priv(const struct bpf_program *prog);\nLIBBPF_API void bpf_program__set_ifindex(struct bpf_program *prog,\n\t\t\t\t\t __u32 ifindex);\n\nLIBBPF_API const char *bpf_program__name(const struct bpf_program *prog);\nLIBBPF_API const char *bpf_program__section_name(const struct bpf_program *prog);\nLIBBPF_API LIBBPF_DEPRECATED(\"BPF program title is confusing term; please use bpf_program__section_name() instead\")\nconst char *bpf_program__title(const struct bpf_program *prog, bool needs_copy);\nLIBBPF_API bool bpf_program__autoload(const struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_autoload(struct bpf_program *prog, bool autoload);\n\n/* returns program size in bytes */\nLIBBPF_API size_t bpf_program__size(const struct bpf_program *prog);\n\nLIBBPF_API int bpf_program__load(struct bpf_program *prog, char *license,\n\t\t\t\t __u32 kern_version);\nLIBBPF_API int bpf_program__fd(const struct bpf_program *prog);\nLIBBPF_API int bpf_program__pin_instance(struct bpf_program *prog,\n\t\t\t\t\t const char *path,\n\t\t\t\t\t int instance);\nLIBBPF_API int bpf_program__unpin_instance(struct bpf_program *prog,\n\t\t\t\t\t   const char *path,\n\t\t\t\t\t   int instance);\nLIBBPF_API int bpf_program__pin(struct bpf_program *prog, const char *path);\nLIBBPF_API int bpf_program__unpin(struct bpf_program *prog, const char *path);\nLIBBPF_API void bpf_program__unload(struct bpf_program *prog);\n\nstruct bpf_link;\n\nLIBBPF_API struct bpf_link *bpf_link__open(const char *path);\nLIBBPF_API int bpf_link__fd(const struct bpf_link *link);\nLIBBPF_API const char *bpf_link__pin_path(const struct bpf_link *link);\nLIBBPF_API int bpf_link__pin(struct bpf_link *link, const char *path);\nLIBBPF_API int bpf_link__unpin(struct bpf_link *link);\nLIBBPF_API int bpf_link__update_program(struct bpf_link *link,\n\t\t\t\t\tstruct bpf_program *prog);\nLIBBPF_API void bpf_link__disconnect(struct bpf_link *link);\nLIBBPF_API int bpf_link__detach(struct bpf_link *link);\nLIBBPF_API int bpf_link__destroy(struct bpf_link *link);\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach(struct bpf_program *prog);\n\nstruct bpf_perf_event_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* custom user-provided value fetchable through bpf_get_attach_cookie() */\n\t__u64 bpf_cookie;\n};\n#define bpf_perf_event_opts__last_field bpf_cookie\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_perf_event(struct bpf_program *prog, int pfd);\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_perf_event_opts(struct bpf_program *prog, int pfd,\n\t\t\t\t    const struct bpf_perf_event_opts *opts);\n\nstruct bpf_kprobe_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* custom user-provided value fetchable through bpf_get_attach_cookie() */\n\t__u64 bpf_cookie;\n\t/* function's offset to install kprobe to */\n\tunsigned long offset;\n\t/* kprobe is return probe */\n\tbool retprobe;\n\tsize_t :0;\n};\n#define bpf_kprobe_opts__last_field retprobe\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_kprobe(struct bpf_program *prog, bool retprobe,\n\t\t\t   const char *func_name);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_kprobe_opts(struct bpf_program *prog,\n                                const char *func_name,\n                                const struct bpf_kprobe_opts *opts);\n\nstruct bpf_uprobe_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* offset of kernel reference counted USDT semaphore, added in\n\t * a6ca88b241d5 (\"trace_uprobe: support reference counter in fd-based uprobe\")\n\t */\n\tsize_t ref_ctr_offset;\n\t/* custom user-provided value fetchable through bpf_get_attach_cookie() */\n\t__u64 bpf_cookie;\n\t/* uprobe is return probe, invoked at function return time */\n\tbool retprobe;\n\tsize_t :0;\n};\n#define bpf_uprobe_opts__last_field retprobe\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_uprobe(struct bpf_program *prog, bool retprobe,\n\t\t\t   pid_t pid, const char *binary_path,\n\t\t\t   size_t func_offset);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_uprobe_opts(struct bpf_program *prog, pid_t pid,\n\t\t\t\tconst char *binary_path, size_t func_offset,\n\t\t\t\tconst struct bpf_uprobe_opts *opts);\n\nstruct bpf_tracepoint_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n\t/* custom user-provided value fetchable through bpf_get_attach_cookie() */\n\t__u64 bpf_cookie;\n};\n#define bpf_tracepoint_opts__last_field bpf_cookie\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_tracepoint(struct bpf_program *prog,\n\t\t\t       const char *tp_category,\n\t\t\t       const char *tp_name);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_tracepoint_opts(struct bpf_program *prog,\n\t\t\t\t    const char *tp_category,\n\t\t\t\t    const char *tp_name,\n\t\t\t\t    const struct bpf_tracepoint_opts *opts);\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_raw_tracepoint(struct bpf_program *prog,\n\t\t\t\t   const char *tp_name);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_trace(struct bpf_program *prog);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_lsm(struct bpf_program *prog);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_cgroup(struct bpf_program *prog, int cgroup_fd);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_netns(struct bpf_program *prog, int netns_fd);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_xdp(struct bpf_program *prog, int ifindex);\nLIBBPF_API struct bpf_link *\nbpf_program__attach_freplace(struct bpf_program *prog,\n\t\t\t     int target_fd, const char *attach_func_name);\n\nstruct bpf_map;\n\nLIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map);\n\nstruct bpf_iter_attach_opts {\n\tsize_t sz; /* size of this struct for forward/backward compatibility */\n\tunion bpf_iter_link_info *link_info;\n\t__u32 link_info_len;\n};\n#define bpf_iter_attach_opts__last_field link_info_len\n\nLIBBPF_API struct bpf_link *\nbpf_program__attach_iter(struct bpf_program *prog,\n\t\t\t const struct bpf_iter_attach_opts *opts);\n\nstruct bpf_insn;\n\n/*\n * Libbpf allows callers to adjust BPF programs before being loaded\n * into kernel. One program in an object file can be transformed into\n * multiple variants to be attached to different hooks.\n *\n * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd\n * form an API for this purpose.\n *\n * - bpf_program_prep_t:\n *   Defines a 'preprocessor', which is a caller defined function\n *   passed to libbpf through bpf_program__set_prep(), and will be\n *   called before program is loaded. The processor should adjust\n *   the program one time for each instance according to the instance id\n *   passed to it.\n *\n * - bpf_program__set_prep:\n *   Attaches a preprocessor to a BPF program. The number of instances\n *   that should be created is also passed through this function.\n *\n * - bpf_program__nth_fd:\n *   After the program is loaded, get resulting FD of a given instance\n *   of the BPF program.\n *\n * If bpf_program__set_prep() is not used, the program would be loaded\n * without adjustment during bpf_object__load(). The program has only\n * one instance. In this case bpf_program__fd(prog) is equal to\n * bpf_program__nth_fd(prog, 0).\n */\n\nstruct bpf_prog_prep_result {\n\t/*\n\t * If not NULL, load new instruction array.\n\t * If set to NULL, don't load this instance.\n\t */\n\tstruct bpf_insn *new_insn_ptr;\n\tint new_insn_cnt;\n\n\t/* If not NULL, result FD is written to it. */\n\tint *pfd;\n};\n\n/*\n * Parameters of bpf_program_prep_t:\n *  - prog:\tThe bpf_program being loaded.\n *  - n:\tIndex of instance being generated.\n *  - insns:\tBPF instructions array.\n *  - insns_cnt:Number of instructions in insns.\n *  - res:\tOutput parameter, result of transformation.\n *\n * Return value:\n *  - Zero:\tpre-processing success.\n *  - Non-zero:\tpre-processing error, stop loading.\n */\ntypedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,\n\t\t\t\t  struct bpf_insn *insns, int insns_cnt,\n\t\t\t\t  struct bpf_prog_prep_result *res);\n\nLIBBPF_API int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,\n\t\t\t\t     bpf_program_prep_t prep);\n\nLIBBPF_API int bpf_program__nth_fd(const struct bpf_program *prog, int n);\n\n/*\n * Adjust type of BPF program. Default is kprobe.\n */\nLIBBPF_API int bpf_program__set_socket_filter(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_tracepoint(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_raw_tracepoint(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_kprobe(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_lsm(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_sched_cls(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_tracing(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_struct_ops(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_extension(struct bpf_program *prog);\nLIBBPF_API int bpf_program__set_sk_lookup(struct bpf_program *prog);\n\nLIBBPF_API enum bpf_prog_type bpf_program__get_type(const struct bpf_program *prog);\nLIBBPF_API void bpf_program__set_type(struct bpf_program *prog,\n\t\t\t\t      enum bpf_prog_type type);\n\nLIBBPF_API enum bpf_attach_type\nbpf_program__get_expected_attach_type(const struct bpf_program *prog);\nLIBBPF_API void\nbpf_program__set_expected_attach_type(struct bpf_program *prog,\n\t\t\t\t      enum bpf_attach_type type);\n\nLIBBPF_API int\nbpf_program__set_attach_target(struct bpf_program *prog, int attach_prog_fd,\n\t\t\t       const char *attach_func_name);\n\nLIBBPF_API bool bpf_program__is_socket_filter(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_tracepoint(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_raw_tracepoint(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_kprobe(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_lsm(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_sched_cls(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_tracing(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_struct_ops(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_extension(const struct bpf_program *prog);\nLIBBPF_API bool bpf_program__is_sk_lookup(const struct bpf_program *prog);\n\n/*\n * No need for __attribute__((packed)), all members of 'bpf_map_def'\n * are all aligned.  In addition, using __attribute__((packed))\n * would trigger a -Wpacked warning message, and lead to an error\n * if -Werror is set.\n */\nstruct bpf_map_def {\n\tunsigned int type;\n\tunsigned int key_size;\n\tunsigned int value_size;\n\tunsigned int max_entries;\n\tunsigned int map_flags;\n};\n\n/*\n * The 'struct bpf_map' in include/linux/bpf.h is internal to the kernel,\n * so no need to worry about a name clash.\n */\nLIBBPF_API struct bpf_map *\nbpf_object__find_map_by_name(const struct bpf_object *obj, const char *name);\n\nLIBBPF_API int\nbpf_object__find_map_fd_by_name(const struct bpf_object *obj, const char *name);\n\n/*\n * Get bpf_map through the offset of corresponding struct bpf_map_def\n * in the BPF object file.\n */\nLIBBPF_API struct bpf_map *\nbpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset);\n\nLIBBPF_API struct bpf_map *\nbpf_map__next(const struct bpf_map *map, const struct bpf_object *obj);\n#define bpf_object__for_each_map(pos, obj)\t\t\\\n\tfor ((pos) = bpf_map__next(NULL, (obj));\t\\\n\t     (pos) != NULL;\t\t\t\t\\\n\t     (pos) = bpf_map__next((pos), (obj)))\n#define bpf_map__for_each bpf_object__for_each_map\n\nLIBBPF_API struct bpf_map *\nbpf_map__prev(const struct bpf_map *map, const struct bpf_object *obj);\n\n/* get/set map FD */\nLIBBPF_API int bpf_map__fd(const struct bpf_map *map);\nLIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);\n/* get map definition */\nLIBBPF_API const struct bpf_map_def *bpf_map__def(const struct bpf_map *map);\n/* get map name */\nLIBBPF_API const char *bpf_map__name(const struct bpf_map *map);\n/* get/set map type */\nLIBBPF_API enum bpf_map_type bpf_map__type(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_type(struct bpf_map *map, enum bpf_map_type type);\n/* get/set map size (max_entries) */\nLIBBPF_API __u32 bpf_map__max_entries(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_max_entries(struct bpf_map *map, __u32 max_entries);\nLIBBPF_API int bpf_map__resize(struct bpf_map *map, __u32 max_entries);\n/* get/set map flags */\nLIBBPF_API __u32 bpf_map__map_flags(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_map_flags(struct bpf_map *map, __u32 flags);\n/* get/set map NUMA node */\nLIBBPF_API __u32 bpf_map__numa_node(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node);\n/* get/set map key size */\nLIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size);\n/* get/set map value size */\nLIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size);\n/* get map key/value BTF type IDs */\nLIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map);\nLIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);\n/* get/set map if_index */\nLIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);\n\ntypedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);\nLIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,\n\t\t\t\t bpf_map_clear_priv_t clear_priv);\nLIBBPF_API void *bpf_map__priv(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map,\n\t\t\t\t\t  const void *data, size_t size);\nLIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize);\nLIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map);\nLIBBPF_API bool bpf_map__is_internal(const struct bpf_map *map);\nLIBBPF_API int bpf_map__set_pin_path(struct bpf_map *map, const char *path);\nLIBBPF_API const char *bpf_map__get_pin_path(const struct bpf_map *map);\nLIBBPF_API const char *bpf_map__pin_path(const struct bpf_map *map);\nLIBBPF_API bool bpf_map__is_pinned(const struct bpf_map *map);\nLIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);\nLIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);\n\nLIBBPF_API int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd);\nLIBBPF_API struct bpf_map *bpf_map__inner_map(struct bpf_map *map);\n\nLIBBPF_API long libbpf_get_error(const void *ptr);\n\nstruct bpf_prog_load_attr {\n\tconst char *file;\n\tenum bpf_prog_type prog_type;\n\tenum bpf_attach_type expected_attach_type;\n\tint ifindex;\n\tint log_level;\n\tint prog_flags;\n};\n\nLIBBPF_API int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,\n\t\t\t\t   struct bpf_object **pobj, int *prog_fd);\nLIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,\n\t\t\t     struct bpf_object **pobj, int *prog_fd);\n\n/* XDP related API */\nstruct xdp_link_info {\n\t__u32 prog_id;\n\t__u32 drv_prog_id;\n\t__u32 hw_prog_id;\n\t__u32 skb_prog_id;\n\t__u8 attach_mode;\n};\n\nstruct bpf_xdp_set_link_opts {\n\tsize_t sz;\n\tint old_fd;\n\tsize_t :0;\n};\n#define bpf_xdp_set_link_opts__last_field old_fd\n\nLIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);\nLIBBPF_API int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,\n\t\t\t\t\tconst struct bpf_xdp_set_link_opts *opts);\nLIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);\nLIBBPF_API int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,\n\t\t\t\t     size_t info_size, __u32 flags);\n\n/* TC related API */\nenum bpf_tc_attach_point {\n\tBPF_TC_INGRESS = 1 << 0,\n\tBPF_TC_EGRESS  = 1 << 1,\n\tBPF_TC_CUSTOM  = 1 << 2,\n};\n\n#define BPF_TC_PARENT(a, b) \t\\\n\t((((a) << 16) & 0xFFFF0000U) | ((b) & 0x0000FFFFU))\n\nenum bpf_tc_flags {\n\tBPF_TC_F_REPLACE = 1 << 0,\n};\n\nstruct bpf_tc_hook {\n\tsize_t sz;\n\tint ifindex;\n\tenum bpf_tc_attach_point attach_point;\n\t__u32 parent;\n\tsize_t :0;\n};\n#define bpf_tc_hook__last_field parent\n\nstruct bpf_tc_opts {\n\tsize_t sz;\n\tint prog_fd;\n\t__u32 flags;\n\t__u32 prog_id;\n\t__u32 handle;\n\t__u32 priority;\n\tsize_t :0;\n};\n#define bpf_tc_opts__last_field priority\n\nLIBBPF_API int bpf_tc_hook_create(struct bpf_tc_hook *hook);\nLIBBPF_API int bpf_tc_hook_destroy(struct bpf_tc_hook *hook);\nLIBBPF_API int bpf_tc_attach(const struct bpf_tc_hook *hook,\n\t\t\t     struct bpf_tc_opts *opts);\nLIBBPF_API int bpf_tc_detach(const struct bpf_tc_hook *hook,\n\t\t\t     const struct bpf_tc_opts *opts);\nLIBBPF_API int bpf_tc_query(const struct bpf_tc_hook *hook,\n\t\t\t    struct bpf_tc_opts *opts);\n\n/* Ring buffer APIs */\nstruct ring_buffer;\n\ntypedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);\n\nstruct ring_buffer_opts {\n\tsize_t sz; /* size of this struct, for forward/backward compatiblity */\n};\n\n#define ring_buffer_opts__last_field sz\n\nLIBBPF_API struct ring_buffer *\nring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx,\n\t\t const struct ring_buffer_opts *opts);\nLIBBPF_API void ring_buffer__free(struct ring_buffer *rb);\nLIBBPF_API int ring_buffer__add(struct ring_buffer *rb, int map_fd,\n\t\t\t\tring_buffer_sample_fn sample_cb, void *ctx);\nLIBBPF_API int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms);\nLIBBPF_API int ring_buffer__consume(struct ring_buffer *rb);\nLIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);\n\n/* Perf buffer APIs */\nstruct perf_buffer;\n\ntypedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,\n\t\t\t\t      void *data, __u32 size);\ntypedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);\n\n/* common use perf buffer options */\nstruct perf_buffer_opts {\n\t/* if specified, sample_cb is called for each sample */\n\tperf_buffer_sample_fn sample_cb;\n\t/* if specified, lost_cb is called for each batch of lost samples */\n\tperf_buffer_lost_fn lost_cb;\n\t/* ctx is provided to sample_cb and lost_cb */\n\tvoid *ctx;\n};\n\nLIBBPF_API struct perf_buffer *\nperf_buffer__new(int map_fd, size_t page_cnt,\n\t\t const struct perf_buffer_opts *opts);\n\nenum bpf_perf_event_ret {\n\tLIBBPF_PERF_EVENT_DONE\t= 0,\n\tLIBBPF_PERF_EVENT_ERROR\t= -1,\n\tLIBBPF_PERF_EVENT_CONT\t= -2,\n};\n\nstruct perf_event_header;\n\ntypedef enum bpf_perf_event_ret\n(*perf_buffer_event_fn)(void *ctx, int cpu, struct perf_event_header *event);\n\n/* raw perf buffer options, giving most power and control */\nstruct perf_buffer_raw_opts {\n\t/* perf event attrs passed directly into perf_event_open() */\n\tstruct perf_event_attr *attr;\n\t/* raw event callback */\n\tperf_buffer_event_fn event_cb;\n\t/* ctx is provided to event_cb */\n\tvoid *ctx;\n\t/* if cpu_cnt == 0, open all on all possible CPUs (up to the number of\n\t * max_entries of given PERF_EVENT_ARRAY map)\n\t */\n\tint cpu_cnt;\n\t/* if cpu_cnt > 0, cpus is an array of CPUs to open ring buffers on */\n\tint *cpus;\n\t/* if cpu_cnt > 0, map_keys specify map keys to set per-CPU FDs for */\n\tint *map_keys;\n};\n\nLIBBPF_API struct perf_buffer *\nperf_buffer__new_raw(int map_fd, size_t page_cnt,\n\t\t     const struct perf_buffer_raw_opts *opts);\n\nLIBBPF_API void perf_buffer__free(struct perf_buffer *pb);\nLIBBPF_API int perf_buffer__epoll_fd(const struct perf_buffer *pb);\nLIBBPF_API int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms);\nLIBBPF_API int perf_buffer__consume(struct perf_buffer *pb);\nLIBBPF_API int perf_buffer__consume_buffer(struct perf_buffer *pb, size_t buf_idx);\nLIBBPF_API size_t perf_buffer__buffer_cnt(const struct perf_buffer *pb);\nLIBBPF_API int perf_buffer__buffer_fd(const struct perf_buffer *pb, size_t buf_idx);\n\ntypedef enum bpf_perf_event_ret\n\t(*bpf_perf_event_print_t)(struct perf_event_header *hdr,\n\t\t\t\t  void *private_data);\nLIBBPF_API enum bpf_perf_event_ret\nbpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,\n\t\t\t   void **copy_mem, size_t *copy_size,\n\t\t\t   bpf_perf_event_print_t fn, void *private_data);\n\nstruct bpf_prog_linfo;\nstruct bpf_prog_info;\n\nLIBBPF_API void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo);\nLIBBPF_API struct bpf_prog_linfo *\nbpf_prog_linfo__new(const struct bpf_prog_info *info);\nLIBBPF_API const struct bpf_line_info *\nbpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,\n\t\t\t\t__u64 addr, __u32 func_idx, __u32 nr_skip);\nLIBBPF_API const struct bpf_line_info *\nbpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,\n\t\t      __u32 insn_off, __u32 nr_skip);\n\n/*\n * Probe for supported system features\n *\n * Note that running many of these probes in a short amount of time can cause\n * the kernel to reach the maximal size of lockable memory allowed for the\n * user, causing subsequent probes to fail. In this case, the caller may want\n * to adjust that limit with setrlimit().\n */\nLIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,\n\t\t\t\t    __u32 ifindex);\nLIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);\nLIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,\n\t\t\t\t enum bpf_prog_type prog_type, __u32 ifindex);\nLIBBPF_API bool bpf_probe_large_insn_limit(__u32 ifindex);\n\n/*\n * Get bpf_prog_info in continuous memory\n *\n * struct bpf_prog_info has multiple arrays. The user has option to choose\n * arrays to fetch from kernel. The following APIs provide an uniform way to\n * fetch these data. All arrays in bpf_prog_info are stored in a single\n * continuous memory region. This makes it easy to store the info in a\n * file.\n *\n * Before writing bpf_prog_info_linear to files, it is necessary to\n * translate pointers in bpf_prog_info to offsets. Helper functions\n * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()\n * are introduced to switch between pointers and offsets.\n *\n * Examples:\n *   # To fetch map_ids and prog_tags:\n *   __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |\n *           (1UL << BPF_PROG_INFO_PROG_TAGS);\n *   struct bpf_prog_info_linear *info_linear =\n *           bpf_program__get_prog_info_linear(fd, arrays);\n *\n *   # To save data in file\n *   bpf_program__bpil_addr_to_offs(info_linear);\n *   write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);\n *\n *   # To read data from file\n *   read(f, info_linear, <proper_size>);\n *   bpf_program__bpil_offs_to_addr(info_linear);\n */\nenum bpf_prog_info_array {\n\tBPF_PROG_INFO_FIRST_ARRAY = 0,\n\tBPF_PROG_INFO_JITED_INSNS = 0,\n\tBPF_PROG_INFO_XLATED_INSNS,\n\tBPF_PROG_INFO_MAP_IDS,\n\tBPF_PROG_INFO_JITED_KSYMS,\n\tBPF_PROG_INFO_JITED_FUNC_LENS,\n\tBPF_PROG_INFO_FUNC_INFO,\n\tBPF_PROG_INFO_LINE_INFO,\n\tBPF_PROG_INFO_JITED_LINE_INFO,\n\tBPF_PROG_INFO_PROG_TAGS,\n\tBPF_PROG_INFO_LAST_ARRAY,\n};\n\nstruct bpf_prog_info_linear {\n\t/* size of struct bpf_prog_info, when the tool is compiled */\n\t__u32\t\t\tinfo_len;\n\t/* total bytes allocated for data, round up to 8 bytes */\n\t__u32\t\t\tdata_len;\n\t/* which arrays are included in data */\n\t__u64\t\t\tarrays;\n\tstruct bpf_prog_info\tinfo;\n\t__u8\t\t\tdata[];\n};\n\nLIBBPF_API struct bpf_prog_info_linear *\nbpf_program__get_prog_info_linear(int fd, __u64 arrays);\n\nLIBBPF_API void\nbpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);\n\nLIBBPF_API void\nbpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);\n\n/*\n * A helper function to get the number of possible CPUs before looking up\n * per-CPU maps. Negative errno is returned on failure.\n *\n * Example usage:\n *\n *     int ncpus = libbpf_num_possible_cpus();\n *     if (ncpus < 0) {\n *          // error handling\n *     }\n *     long values[ncpus];\n *     bpf_map_lookup_elem(per_cpu_map_fd, key, values);\n *\n */\nLIBBPF_API int libbpf_num_possible_cpus(void);\n\nstruct bpf_map_skeleton {\n\tconst char *name;\n\tstruct bpf_map **map;\n\tvoid **mmaped;\n};\n\nstruct bpf_prog_skeleton {\n\tconst char *name;\n\tstruct bpf_program **prog;\n\tstruct bpf_link **link;\n};\n\nstruct bpf_object_skeleton {\n\tsize_t sz; /* size of this struct, for forward/backward compatibility */\n\n\tconst char *name;\n\tconst void *data;\n\tsize_t data_sz;\n\n\tstruct bpf_object **obj;\n\n\tint map_cnt;\n\tint map_skel_sz; /* sizeof(struct bpf_skeleton_map) */\n\tstruct bpf_map_skeleton *maps;\n\n\tint prog_cnt;\n\tint prog_skel_sz; /* sizeof(struct bpf_skeleton_prog) */\n\tstruct bpf_prog_skeleton *progs;\n};\n\nLIBBPF_API int\nbpf_object__open_skeleton(struct bpf_object_skeleton *s,\n\t\t\t  const struct bpf_object_open_opts *opts);\nLIBBPF_API int bpf_object__load_skeleton(struct bpf_object_skeleton *s);\nLIBBPF_API int bpf_object__attach_skeleton(struct bpf_object_skeleton *s);\nLIBBPF_API void bpf_object__detach_skeleton(struct bpf_object_skeleton *s);\nLIBBPF_API void bpf_object__destroy_skeleton(struct bpf_object_skeleton *s);\n\nstruct gen_loader_opts {\n\tsize_t sz; /* size of this struct, for forward/backward compatiblity */\n\tconst char *data;\n\tconst char *insns;\n\t__u32 data_sz;\n\t__u32 insns_sz;\n};\n\n#define gen_loader_opts__last_field insns_sz\nLIBBPF_API int bpf_object__gen_loader(struct bpf_object *obj,\n\t\t\t\t      struct gen_loader_opts *opts);\n\nenum libbpf_tristate {\n\tTRI_NO = 0,\n\tTRI_YES = 1,\n\tTRI_MODULE = 2,\n};\n\nstruct bpf_linker_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n};\n#define bpf_linker_opts__last_field sz\n\nstruct bpf_linker_file_opts {\n\t/* size of this struct, for forward/backward compatiblity */\n\tsize_t sz;\n};\n#define bpf_linker_file_opts__last_field sz\n\nstruct bpf_linker;\n\nLIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts);\nLIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,\n\t\t\t\t    const char *filename,\n\t\t\t\t    const struct bpf_linker_file_opts *opts);\nLIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);\nLIBBPF_API void bpf_linker__free(struct bpf_linker *linker);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* __LIBBPF_LIBBPF_H */\n"
  },
  {
    "path": "include/libbpf/libbpf_common.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n\n/*\n * Common user-facing libbpf helpers.\n *\n * Copyright (c) 2019 Facebook\n */\n\n#ifndef __LIBBPF_LIBBPF_COMMON_H\n#define __LIBBPF_LIBBPF_COMMON_H\n\n#include <string.h>\n\n#ifndef LIBBPF_API\n#define LIBBPF_API __attribute__((visibility(\"default\")))\n#endif\n\n#define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))\n\n/* Helper macro to declare and initialize libbpf options struct\n *\n * This dance with uninitialized declaration, followed by memset to zero,\n * followed by assignment using compound literal syntax is done to preserve\n * ability to use a nice struct field initialization syntax and **hopefully**\n * have all the padding bytes initialized to zero. It's not guaranteed though,\n * when copying literal, that compiler won't copy garbage in literal's padding\n * bytes, but that's the best way I've found and it seems to work in practice.\n *\n * Macro declares opts struct of given type and name, zero-initializes,\n * including any extra padding, it with memset() and then assigns initial\n * values provided by users in struct initializer-syntax as varargs.\n */\n#define DECLARE_LIBBPF_OPTS(TYPE, NAME, ...)\t\t\t\t    \\\n\tstruct TYPE NAME = ({ \t\t\t\t\t\t    \\\n\t\tmemset(&NAME, 0, sizeof(struct TYPE));\t\t\t    \\\n\t\t(struct TYPE) {\t\t\t\t\t\t    \\\n\t\t\t.sz = sizeof(struct TYPE),\t\t\t    \\\n\t\t\t__VA_ARGS__\t\t\t\t\t    \\\n\t\t};\t\t\t\t\t\t\t    \\\n\t})\n\n#endif /* __LIBBPF_LIBBPF_COMMON_H */\n"
  },
  {
    "path": "include/libbpf/libbpf_legacy.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n\n/*\n * Libbpf legacy APIs (either discouraged or deprecated, as mentioned in [0])\n *\n *   [0] https://docs.google.com/document/d/1UyjTZuPFWiPFyKk1tV5an11_iaRuec6U-ZESZ54nNTY\n *\n * Copyright (C) 2021 Facebook\n */\n#ifndef __LIBBPF_LEGACY_BPF_H\n#define __LIBBPF_LEGACY_BPF_H\n\n#include <linux/bpf.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include \"libbpf_common.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum libbpf_strict_mode {\n\t/* Turn on all supported strict features of libbpf to simulate libbpf\n\t * v1.0 behavior.\n\t * This will be the default behavior in libbpf v1.0.\n\t */\n\tLIBBPF_STRICT_ALL = 0xffffffff,\n\n\t/*\n\t * Disable any libbpf 1.0 behaviors. This is the default before libbpf\n\t * v1.0. It won't be supported anymore in v1.0, please update your\n\t * code so that it handles LIBBPF_STRICT_ALL mode before libbpf v1.0.\n\t */\n\tLIBBPF_STRICT_NONE = 0x00,\n\t/*\n\t * Return NULL pointers on error, not ERR_PTR(err).\n\t * Additionally, libbpf also always sets errno to corresponding Exx\n\t * (positive) error code.\n\t */\n\tLIBBPF_STRICT_CLEAN_PTRS = 0x01,\n\t/*\n\t * Return actual error codes from low-level APIs directly, not just -1.\n\t * Additionally, libbpf also always sets errno to corresponding Exx\n\t * (positive) error code.\n\t */\n\tLIBBPF_STRICT_DIRECT_ERRS = 0x02,\n\n\t__LIBBPF_STRICT_LAST,\n};\n\nLIBBPF_API int libbpf_set_strict_mode(enum libbpf_strict_mode mode);\n\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* __LIBBPF_LEGACY_BPF_H */\n"
  },
  {
    "path": "include/libbpf/libbpf_version.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n/* Copyright (C) 2021 Facebook */\n#ifndef __LIBBPF_VERSION_H\n#define __LIBBPF_VERSION_H\n\n#define LIBBPF_MAJOR_VERSION 0\n#define LIBBPF_MINOR_VERSION 7\n\n#endif /* __LIBBPF_VERSION_H */\n"
  },
  {
    "path": "include/libbpf/skel_internal.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n/* Copyright (c) 2021 Facebook */\n#ifndef __SKEL_INTERNAL_H\n#define __SKEL_INTERNAL_H\n\n#include <unistd.h>\n#include <sys/syscall.h>\n#include <sys/mman.h>\n\n/* This file is a base header for auto-generated *.lskel.h files.\n * Its contents will change and may become part of auto-generation in the future.\n *\n * The layout of bpf_[map|prog]_desc and bpf_loader_ctx is feature dependent\n * and will change from one version of libbpf to another and features\n * requested during loader program generation.\n */\nstruct bpf_map_desc {\n\tunion {\n\t\t/* input for the loader prog */\n\t\tstruct {\n\t\t\t__aligned_u64 initial_value;\n\t\t\t__u32 max_entries;\n\t\t};\n\t\t/* output of the loader prog */\n\t\tstruct {\n\t\t\tint map_fd;\n\t\t};\n\t};\n};\nstruct bpf_prog_desc {\n\tint prog_fd;\n};\n\nstruct bpf_loader_ctx {\n\tsize_t sz;\n\t__u32 log_level;\n\t__u32 log_size;\n\t__u64 log_buf;\n};\n\nstruct bpf_load_and_run_opts {\n\tstruct bpf_loader_ctx *ctx;\n\tconst void *data;\n\tconst void *insns;\n\t__u32 data_sz;\n\t__u32 insns_sz;\n\tconst char *errstr;\n};\n\nstatic inline int skel_sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,\n\t\t\t  unsigned int size)\n{\n\treturn syscall(__NR_bpf, cmd, attr, size);\n}\n\nstatic inline int skel_closenz(int fd)\n{\n\tif (fd > 0)\n\t\treturn close(fd);\n\treturn -EINVAL;\n}\n\nstatic inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)\n{\n\tint map_fd = -1, prog_fd = -1, key = 0, err;\n\tunion bpf_attr attr;\n\n\tmap_fd = bpf_create_map_name(BPF_MAP_TYPE_ARRAY, \"__loader.map\", 4,\n\t\t\t\t     opts->data_sz, 1, 0);\n\tif (map_fd < 0) {\n\t\topts->errstr = \"failed to create loader map\";\n\t\terr = -errno;\n\t\tgoto out;\n\t}\n\n\terr = bpf_map_update_elem(map_fd, &key, opts->data, 0);\n\tif (err < 0) {\n\t\topts->errstr = \"failed to update loader map\";\n\t\terr = -errno;\n\t\tgoto out;\n\t}\n\n\tmemset(&attr, 0, sizeof(attr));\n\tattr.prog_type = BPF_PROG_TYPE_SYSCALL;\n\tattr.insns = (long) opts->insns;\n\tattr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);\n\tattr.license = (long) \"Dual BSD/GPL\";\n\tmemcpy(attr.prog_name, \"__loader.prog\", sizeof(\"__loader.prog\"));\n\tattr.fd_array = (long) &map_fd;\n\tattr.log_level = opts->ctx->log_level;\n\tattr.log_size = opts->ctx->log_size;\n\tattr.log_buf = opts->ctx->log_buf;\n\tattr.prog_flags = BPF_F_SLEEPABLE;\n\tprog_fd = skel_sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));\n\tif (prog_fd < 0) {\n\t\topts->errstr = \"failed to load loader prog\";\n\t\terr = -errno;\n\t\tgoto out;\n\t}\n\n\tmemset(&attr, 0, sizeof(attr));\n\tattr.test.prog_fd = prog_fd;\n\tattr.test.ctx_in = (long) opts->ctx;\n\tattr.test.ctx_size_in = opts->ctx->sz;\n\terr = skel_sys_bpf(BPF_PROG_RUN, &attr, sizeof(attr));\n\tif (err < 0 || (int)attr.test.retval < 0) {\n\t\topts->errstr = \"failed to execute loader prog\";\n\t\tif (err < 0)\n\t\t\terr = -errno;\n\t\telse\n\t\t\terr = (int)attr.test.retval;\n\t\tgoto out;\n\t}\n\terr = 0;\nout:\n\tif (map_fd >= 0)\n\t\tclose(map_fd);\n\tif (prog_fd >= 0)\n\t\tclose(prog_fd);\n\treturn err;\n}\n\n#endif\n"
  },
  {
    "path": "include/libbpf/xsk.h",
    "content": "/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */\n\n/*\n * AF_XDP user-space access library.\n *\n * Copyright (c) 2018 - 2019 Intel Corporation.\n * Copyright (c) 2019 Facebook\n *\n * Author(s): Magnus Karlsson <magnus.karlsson@intel.com>\n */\n\n#ifndef __LIBBPF_XSK_H\n#define __LIBBPF_XSK_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <linux/if_xdp.h>\n\n#include \"libbpf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Load-Acquire Store-Release barriers used by the XDP socket\n * library. The following macros should *NOT* be considered part of\n * the xsk.h API, and is subject to change anytime.\n *\n * LIBRARY INTERNAL\n */\n\n#define __XSK_READ_ONCE(x) (*(volatile typeof(x) *)&x)\n#define __XSK_WRITE_ONCE(x, v) (*(volatile typeof(x) *)&x) = (v)\n\n#if defined(__i386__) || defined(__x86_64__)\n# define libbpf_smp_store_release(p, v)\t\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\\\n\t\tasm volatile(\"\" : : : \"memory\");\t\t\t\\\n\t\t__XSK_WRITE_ONCE(*p, v);\t\t\t\t\\\n\t} while (0)\n# define libbpf_smp_load_acquire(p)\t\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\t\\\n\t\ttypeof(*p) ___p1 = __XSK_READ_ONCE(*p);\t\t\t\\\n\t\tasm volatile(\"\" : : : \"memory\");\t\t\t\\\n\t\t___p1;\t\t\t\t\t\t\t\\\n\t})\n#elif defined(__aarch64__)\n# define libbpf_smp_store_release(p, v)\t\t\t\t\t\\\n\t\tasm volatile (\"stlr %w1, %0\" : \"=Q\" (*p) : \"r\" (v) : \"memory\")\n# define libbpf_smp_load_acquire(p)\t\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\t\\\n\t\ttypeof(*p) ___p1;\t\t\t\t\t\\\n\t\tasm volatile (\"ldar %w0, %1\"\t\t\t\t\\\n\t\t\t      : \"=r\" (___p1) : \"Q\" (*p) : \"memory\");\t\\\n\t\t___p1;\t\t\t\t\t\t\t\\\n\t})\n#elif defined(__riscv)\n# define libbpf_smp_store_release(p, v)\t\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\\\n\t\tasm volatile (\"fence rw,w\" : : : \"memory\");\t\t\\\n\t\t__XSK_WRITE_ONCE(*p, v);\t\t\t\t\\\n\t} while (0)\n# define libbpf_smp_load_acquire(p)\t\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\t\\\n\t\ttypeof(*p) ___p1 = __XSK_READ_ONCE(*p);\t\t\t\\\n\t\tasm volatile (\"fence r,rw\" : : : \"memory\");\t\t\\\n\t\t___p1;\t\t\t\t\t\t\t\\\n\t})\n#endif\n\n#ifndef libbpf_smp_store_release\n#define libbpf_smp_store_release(p, v)\t\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\\\n\t\t__sync_synchronize();\t\t\t\t\t\\\n\t\t__XSK_WRITE_ONCE(*p, v);\t\t\t\t\\\n\t} while (0)\n#endif\n\n#ifndef libbpf_smp_load_acquire\n#define libbpf_smp_load_acquire(p)\t\t\t\t\t\\\n\t({\t\t\t\t\t\t\t\t\\\n\t\ttypeof(*p) ___p1 = __XSK_READ_ONCE(*p);\t\t\t\\\n\t\t__sync_synchronize();\t\t\t\t\t\\\n\t\t___p1;\t\t\t\t\t\t\t\\\n\t})\n#endif\n\n/* LIBRARY INTERNAL -- END */\n\n/* Do not access these members directly. Use the functions below. */\n#define DEFINE_XSK_RING(name) \\\nstruct name { \\\n\t__u32 cached_prod; \\\n\t__u32 cached_cons; \\\n\t__u32 mask; \\\n\t__u32 size; \\\n\t__u32 *producer; \\\n\t__u32 *consumer; \\\n\tvoid *ring; \\\n\t__u32 *flags; \\\n}\n\nDEFINE_XSK_RING(xsk_ring_prod);\nDEFINE_XSK_RING(xsk_ring_cons);\n\n/* For a detailed explanation on the memory barriers associated with the\n * ring, please take a look at net/xdp/xsk_queue.h.\n */\n\nstruct xsk_umem;\nstruct xsk_socket;\n\nstatic inline __u64 *xsk_ring_prod__fill_addr(struct xsk_ring_prod *fill,\n\t\t\t\t\t      __u32 idx)\n{\n\t__u64 *addrs = (__u64 *)fill->ring;\n\n\treturn &addrs[idx & fill->mask];\n}\n\nstatic inline const __u64 *\nxsk_ring_cons__comp_addr(const struct xsk_ring_cons *comp, __u32 idx)\n{\n\tconst __u64 *addrs = (const __u64 *)comp->ring;\n\n\treturn &addrs[idx & comp->mask];\n}\n\nstatic inline struct xdp_desc *xsk_ring_prod__tx_desc(struct xsk_ring_prod *tx,\n\t\t\t\t\t\t      __u32 idx)\n{\n\tstruct xdp_desc *descs = (struct xdp_desc *)tx->ring;\n\n\treturn &descs[idx & tx->mask];\n}\n\nstatic inline const struct xdp_desc *\nxsk_ring_cons__rx_desc(const struct xsk_ring_cons *rx, __u32 idx)\n{\n\tconst struct xdp_desc *descs = (const struct xdp_desc *)rx->ring;\n\n\treturn &descs[idx & rx->mask];\n}\n\nstatic inline int xsk_ring_prod__needs_wakeup(const struct xsk_ring_prod *r)\n{\n\treturn *r->flags & XDP_RING_NEED_WAKEUP;\n}\n\nstatic inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb)\n{\n\t__u32 free_entries = r->cached_cons - r->cached_prod;\n\n\tif (free_entries >= nb)\n\t\treturn free_entries;\n\n\t/* Refresh the local tail pointer.\n\t * cached_cons is r->size bigger than the real consumer pointer so\n\t * that this addition can be avoided in the more frequently\n\t * executed code that computs free_entries in the beginning of\n\t * this function. Without this optimization it whould have been\n\t * free_entries = r->cached_prod - r->cached_cons + r->size.\n\t */\n\tr->cached_cons = libbpf_smp_load_acquire(r->consumer);\n\tr->cached_cons += r->size;\n\n\treturn r->cached_cons - r->cached_prod;\n}\n\nstatic inline __u32 xsk_cons_nb_avail(struct xsk_ring_cons *r, __u32 nb)\n{\n\t__u32 entries = r->cached_prod - r->cached_cons;\n\n\tif (entries == 0) {\n\t\tr->cached_prod = libbpf_smp_load_acquire(r->producer);\n\t\tentries = r->cached_prod - r->cached_cons;\n\t}\n\n\treturn (entries > nb) ? nb : entries;\n}\n\nstatic inline __u32 xsk_ring_prod__reserve(struct xsk_ring_prod *prod, __u32 nb, __u32 *idx)\n{\n\tif (xsk_prod_nb_free(prod, nb) < nb)\n\t\treturn 0;\n\n\t*idx = prod->cached_prod;\n\tprod->cached_prod += nb;\n\n\treturn nb;\n}\n\nstatic inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, __u32 nb)\n{\n\t/* Make sure everything has been written to the ring before indicating\n\t * this to the kernel by writing the producer pointer.\n\t */\n\tlibbpf_smp_store_release(prod->producer, *prod->producer + nb);\n}\n\nstatic inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx)\n{\n\t__u32 entries = xsk_cons_nb_avail(cons, nb);\n\n\tif (entries > 0) {\n\t\t*idx = cons->cached_cons;\n\t\tcons->cached_cons += entries;\n\t}\n\n\treturn entries;\n}\n\nstatic inline void xsk_ring_cons__cancel(struct xsk_ring_cons *cons, __u32 nb)\n{\n\tcons->cached_cons -= nb;\n}\n\nstatic inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, __u32 nb)\n{\n\t/* Make sure data has been read before indicating we are done\n\t * with the entries by updating the consumer pointer.\n\t */\n\tlibbpf_smp_store_release(cons->consumer, *cons->consumer + nb);\n\n}\n\nstatic inline void *xsk_umem__get_data(void *umem_area, __u64 addr)\n{\n\treturn &((char *)umem_area)[addr];\n}\n\nstatic inline __u64 xsk_umem__extract_addr(__u64 addr)\n{\n\treturn addr & XSK_UNALIGNED_BUF_ADDR_MASK;\n}\n\nstatic inline __u64 xsk_umem__extract_offset(__u64 addr)\n{\n\treturn addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;\n}\n\nstatic inline __u64 xsk_umem__add_offset_to_addr(__u64 addr)\n{\n\treturn xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr);\n}\n\nLIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem);\nLIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk);\n\n#define XSK_RING_CONS__DEFAULT_NUM_DESCS      2048\n#define XSK_RING_PROD__DEFAULT_NUM_DESCS      2048\n#define XSK_UMEM__DEFAULT_FRAME_SHIFT    12 /* 4096 bytes */\n#define XSK_UMEM__DEFAULT_FRAME_SIZE     (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT)\n#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0\n#define XSK_UMEM__DEFAULT_FLAGS 0\n\nstruct xsk_umem_config {\n\t__u32 fill_size;\n\t__u32 comp_size;\n\t__u32 frame_size;\n\t__u32 frame_headroom;\n\t__u32 flags;\n};\n\nLIBBPF_API int xsk_setup_xdp_prog(int ifindex,\n\t\t\t\t  int *xsks_map_fd);\nLIBBPF_API int xsk_socket__update_xskmap(struct xsk_socket *xsk,\n\t\t\t\t\t int xsks_map_fd);\n\n/* Flags for the libbpf_flags field. */\n#define XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD (1 << 0)\n\nstruct xsk_socket_config {\n\t__u32 rx_size;\n\t__u32 tx_size;\n\t__u32 libbpf_flags;\n\t__u32 xdp_flags;\n\t__u16 bind_flags;\n};\n\n/* Set config to NULL to get the default configuration. */\nLIBBPF_API int xsk_umem__create(struct xsk_umem **umem,\n\t\t\t\tvoid *umem_area, __u64 size,\n\t\t\t\tstruct xsk_ring_prod *fill,\n\t\t\t\tstruct xsk_ring_cons *comp,\n\t\t\t\tconst struct xsk_umem_config *config);\nLIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem,\n\t\t\t\t       void *umem_area, __u64 size,\n\t\t\t\t       struct xsk_ring_prod *fill,\n\t\t\t\t       struct xsk_ring_cons *comp,\n\t\t\t\t       const struct xsk_umem_config *config);\nLIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem,\n\t\t\t\t       void *umem_area, __u64 size,\n\t\t\t\t       struct xsk_ring_prod *fill,\n\t\t\t\t       struct xsk_ring_cons *comp,\n\t\t\t\t       const struct xsk_umem_config *config);\nLIBBPF_API int xsk_socket__create(struct xsk_socket **xsk,\n\t\t\t\t  const char *ifname, __u32 queue_id,\n\t\t\t\t  struct xsk_umem *umem,\n\t\t\t\t  struct xsk_ring_cons *rx,\n\t\t\t\t  struct xsk_ring_prod *tx,\n\t\t\t\t  const struct xsk_socket_config *config);\nLIBBPF_API int\nxsk_socket__create_shared(struct xsk_socket **xsk_ptr,\n\t\t\t  const char *ifname,\n\t\t\t  __u32 queue_id, struct xsk_umem *umem,\n\t\t\t  struct xsk_ring_cons *rx,\n\t\t\t  struct xsk_ring_prod *tx,\n\t\t\t  struct xsk_ring_prod *fill,\n\t\t\t  struct xsk_ring_cons *comp,\n\t\t\t  const struct xsk_socket_config *config);\n\n/* Returns 0 for success and -EBUSY if the umem is still in use. */\nLIBBPF_API int xsk_umem__delete(struct xsk_umem *umem);\nLIBBPF_API void xsk_socket__delete(struct xsk_socket *xsk);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif /* __LIBBPF_XSK_H */\n"
  },
  {
    "path": "include/span_context.h",
    "content": "#include \"utils.h\"\n\n#define SPAN_CONTEXT_STRING_SIZE 55\n#define MAX_CONCURRENT_SPANS 100\n\nstruct span_context {\n    unsigned char TraceID[TRACE_ID_SIZE];\n    unsigned char SpanID[SPAN_ID_SIZE];\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, void*);\n\t__type(value, struct span_context);\n\t__uint(max_entries, MAX_CONCURRENT_SPANS);\n\t__uint(pinning, LIBBPF_PIN_BY_NAME);\n} spans_in_progress SEC(\".maps\");\n\nstatic __always_inline struct span_context generate_span_context() {\n    struct span_context context = {};\n    generate_random_bytes(context.TraceID, TRACE_ID_SIZE);\n    generate_random_bytes(context.SpanID, SPAN_ID_SIZE);\n    return context;\n}\n\nstatic __always_inline void span_context_to_w3c_string(struct span_context *ctx, char* buff) {\n    // W3C format: version (2 chars) - trace id (32 chars) - span id (16 chars) - sampled (2 chars)\n    char *out = buff;\n\n    // Write version\n    *out++ = '0';\n    *out++ = '0';\n    *out++ = '-';\n\n    // Write trace id\n    bytes_to_hex_string(ctx->TraceID, TRACE_ID_SIZE, out);\n    out += TRACE_ID_STRING_SIZE;\n    *out++ = '-';\n\n    // Write span id\n    bytes_to_hex_string(ctx->SpanID, SPAN_ID_SIZE, out);\n    out += SPAN_ID_STRING_SIZE;\n    *out++ = '-';\n\n    // Write sampled\n    *out++ = '0';\n    *out   = '1';\n}\n\nstatic __always_inline void w3c_string_to_span_context(char *str, struct span_context *ctx) {\n    u32 trace_id_start_pos = 3;\n    u32 span_id_start_pod = 36;\n    hex_string_to_bytes(str+trace_id_start_pos, TRACE_ID_STRING_SIZE, ctx->TraceID);\n    hex_string_to_bytes(str+span_id_start_pod, SPAN_ID_STRING_SIZE, ctx->SpanID);\n}"
  },
  {
    "path": "include/utils.h",
    "content": "#include \"bpf_helpers.h\"\n\n#define TRACE_ID_SIZE 16\n#define TRACE_ID_STRING_SIZE 32\n#define SPAN_ID_SIZE 8\n#define SPAN_ID_STRING_SIZE 16\n\nstatic __always_inline bool bpf_memcmp(char* s1, char* s2, s32 size) {\n    for (int i = 0; i < size; i++) {\n        if (s1[i] != s2[i]) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nstatic __always_inline void generate_random_bytes(unsigned char* buff, u32 size) {\n    for (int i = 0; i < (size / 4); i++) {\n        u32 random = bpf_get_prandom_u32();\n        buff[(4 * i)] = (random >> 24) & 0xFF;\n        buff[(4 * i) + 1] = (random >> 16) & 0xFF;\n        buff[(4 * i) + 2] = (random >> 8) & 0xFF;\n        buff[(4 * i) + 3] = random & 0xFF;\n    }\n}\n\nchar hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};\nstatic __always_inline void bytes_to_hex_string(unsigned char* pin, u32 size, char* out) {\n    char *pout = out;\n    int out_index = 0;\n    for(u32 i = 0; i < size; i++){\n        *pout++ = hex[(*pin>>4)&0xF];\n        *pout++ = hex[(*pin++)&0xF];\n    }\n}\n\nstatic __always_inline void hex_string_to_bytes(char* str, u32 size, unsigned char* out) {\n    for (int i = 0; i < (size / 2); i++) {\n        char ch0 = str[2 * i];\n        char ch1 = str[2 * i + 1];\n        u8 nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);\n        u8 nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);\n        out[i] = (nib0 << 4) | nib1;\n    }\n}\n\nstatic __always_inline void copy_byte_arrays(unsigned char *src, unsigned char *dst, u32 size) {\n    for (int i = 0; i < size; i++) {\n        dst[i] = src[i];\n    }\n}"
  },
  {
    "path": "pkg/errors/errors.go",
    "content": "package errors\n\nimport \"errors\"\n\n// ErrInterrupted can be used as an error to signal that a process was\n// interrupted but didn't fail in any other way.\nvar ErrInterrupted = errors.New(\"interrupted\")\nvar ErrProcessNotFound = errors.New(\"process_not_found\")\nvar ErrABIWrongInstruction = errors.New(\"could not detect ABI, got wrong instruction\")\n"
  },
  {
    "path": "pkg/inject/data.go",
    "content": "package inject\n\ntype TrackedOffsets struct {\n\tData []TrackedLibrary `json:\"data\"`\n}\n\ntype TrackedLibrary struct {\n\tName        string              `json:\"name\"`\n\tDataMembers []TrackedDataMember `json:\"data_members\"`\n}\n\ntype TrackedDataMember struct {\n\tStruct  string            `json:\"struct\"`\n\tField   string            `json:\"field_name\"`\n\tOffsets []VersionedOffset `json:\"offsets\"`\n}\n\ntype VersionedOffset struct {\n\tOffset  uint64 `json:\"offset\"`\n\tVersion string `json:\"version\"`\n}\n"
  },
  {
    "path": "pkg/inject/injector.go",
    "content": "package inject\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process\"\n\t\"runtime\"\n)\n\nvar (\n\t//go:embed offset_results.json\n\toffsetsData string\n)\n\ntype Injector struct {\n\tdata      *TrackedOffsets\n\tisRegAbi  bool\n\tTotalCPUs uint32\n\tStartAddr uint64\n\tEndAddr   uint64\n}\n\nfunc New(target *process.TargetDetails) (*Injector, error) {\n\tvar offsets TrackedOffsets\n\terr := json.Unmarshal([]byte(offsetsData), &offsets)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Injector{\n\t\tdata:      &offsets,\n\t\tisRegAbi:  target.IsRegistersABI(),\n\t\tTotalCPUs: uint32(runtime.NumCPU()),\n\t\tStartAddr: target.AllocationDetails.Addr,\n\t\tEndAddr:   target.AllocationDetails.EndAddr,\n\t}, nil\n}\n\ntype loadBpfFunc func() (*ebpf.CollectionSpec, error)\n\ntype InjectStructField struct {\n\tVarName    string\n\tStructName string\n\tField      string\n}\n\nfunc (i *Injector) Inject(loadBpf loadBpfFunc, library string, libVersion string, fields []*InjectStructField, initAlloc bool) (*ebpf.CollectionSpec, error) {\n\tspec, err := loadBpf()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinjectedVars := make(map[string]interface{})\n\n\tfor _, dm := range fields {\n\t\toffset, found := i.getFieldOffset(library, libVersion, dm.StructName, dm.Field)\n\t\tif !found {\n\t\t\tlog.Logger.V(0).Info(\"could not find offset\", \"lib\", library, \"version\", libVersion, \"struct\", dm.StructName, \"field\", dm.Field)\n\t\t} else {\n\t\t\tinjectedVars[dm.VarName] = offset\n\t\t}\n\t}\n\n\ti.addCommonInjections(injectedVars, initAlloc)\n\tlog.Logger.V(0).Info(\"Injecting variables\", \"vars\", injectedVars)\n\tif len(injectedVars) > 0 {\n\t\terr = spec.RewriteConstants(injectedVars)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn spec, nil\n}\n\nfunc (i *Injector) addCommonInjections(varsMap map[string]interface{}, initAlloc bool) {\n\tvarsMap[\"is_registers_abi\"] = i.isRegAbi\n\tif initAlloc {\n\t\tvarsMap[\"total_cpus\"] = i.TotalCPUs\n\t\tvarsMap[\"start_addr\"] = i.StartAddr\n\t\tvarsMap[\"end_addr\"] = i.EndAddr\n\t}\n}\n\nfunc (i *Injector) getFieldOffset(libName string, libVersion string, structName string, fieldName string) (uint64, bool) {\n\tfor _, l := range i.data.Data {\n\t\tif l.Name == libName {\n\t\t\tfor _, dm := range l.DataMembers {\n\t\t\t\tif dm.Struct == structName && dm.Field == fieldName {\n\t\t\t\t\tfor _, o := range dm.Offsets {\n\t\t\t\t\t\tif o.Version == libVersion {\n\t\t\t\t\t\t\treturn o.Offset, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0, false\n}\n"
  },
  {
    "path": "pkg/inject/offset_results.json",
    "content": "{\n  \"data\": [\n    {\n      \"name\": \"go\",\n      \"data_members\": [\n        {\n          \"struct\": \"net/http.Request\",\n          \"field_name\": \"Method\",\n          \"offsets\": [\n            {\n              \"offset\": 0,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"1.12\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"net/http.Request\",\n          \"field_name\": \"URL\",\n          \"offsets\": [\n            {\n              \"offset\": 16,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 16,\n              \"version\": \"1.12\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"net/http.Request\",\n          \"field_name\": \"RemoteAddr\",\n          \"offsets\": [\n            {\n              \"offset\": 176,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 176,\n              \"version\": \"1.12\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"net/http.Request\",\n          \"field_name\": \"ctx\",\n          \"offsets\": [\n            {\n              \"offset\": 232,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 232,\n              \"version\": \"1.12\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"net/url.URL\",\n          \"field_name\": \"Path\",\n          \"offsets\": [\n            {\n              \"offset\": 56,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 56,\n              \"version\": \"1.12\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"runtime.g\",\n          \"field_name\": \"goid\",\n          \"offsets\": [\n            {\n              \"offset\": 152,\n              \"version\": \"1.20\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.19\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.18\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.17\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.16\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.17\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.16\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.15\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.14\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.13\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.12\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.11\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.10\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.9\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.8\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.7\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.6\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.5\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.4\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.3\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.2\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12.1\"\n            },\n            {\n              \"offset\": 152,\n              \"version\": \"1.12\"\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"name\": \"google.golang.org/grpc\",\n      \"data_members\": [\n        {\n          \"struct\": \"golang.org/x/net/http2.MetaHeadersFrame\",\n          \"field_name\": \"Fields\",\n          \"offsets\": [\n            {\n              \"offset\": 8,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"golang.org/x/net/http2.FrameHeader\",\n          \"field_name\": \"StreamID\",\n          \"offsets\": [\n            {\n              \"offset\": 8,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 8,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"google.golang.org/grpc/internal/transport.Stream\",\n          \"field_name\": \"method\",\n          \"offsets\": [\n            {\n              \"offset\": 80,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 64,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 72,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 80,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"google.golang.org/grpc/internal/transport.Stream\",\n          \"field_name\": \"id\",\n          \"offsets\": [\n            {\n              \"offset\": 0,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 0,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"google.golang.org/grpc/internal/transport.Stream\",\n          \"field_name\": \"ctx\",\n          \"offsets\": [\n            {\n              \"offset\": 32,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 32,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        },\n        {\n          \"struct\": \"google.golang.org/grpc.ClientConn\",\n          \"field_name\": \"target\",\n          \"offsets\": [\n            {\n              \"offset\": 24,\n              \"version\": \"v1.3.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.4.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.4.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.4.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.5.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.5.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.5.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.6.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.4\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.7.5\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.8.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.8.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.9.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.9.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.9.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.10.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.10.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.11.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.11.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.11.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.11.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.12.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.12.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.12.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.13.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.14.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.15.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.16.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.17.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.18.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.18.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.19.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.19.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.20.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.20.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.21.4\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.22.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.23.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.23.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.24.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.25.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.25.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.26.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.27.0-pre\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.27.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.27.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.28.0-pre\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.28.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.28.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.29.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.29.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.29.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.30.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.30.0-dev.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.30.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.30.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.31.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.31.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.31.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.32.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.32.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.33.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.33.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.33.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.33.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.33.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.34.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.34.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.34.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.34.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.35.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.35.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.35.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.36.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.36.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.36.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.37.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.37.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.37.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.38.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.38.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.38.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.39.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.39.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.39.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.40.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.40.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.40.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.41.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.41.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.41.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.42.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.42.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.43.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.43.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.44.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.44.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.45.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.45.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.46.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.46.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.46.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.46.2\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.47.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.47.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.48.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.48.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.49.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.49.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.50.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.50.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.50.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.51.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.51.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.52.0-dev\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.52.0\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.52.1\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.52.3\"\n            },\n            {\n              \"offset\": 24,\n              \"version\": \"v1.53.0-dev\"\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "pkg/instrumentors/allocator/allocator_linux.go",
    "content": "package allocator\n\nimport (\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpffs\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"golang.org/x/sys/unix\"\n\t\"os\"\n)\n\ntype Allocator struct{}\n\nfunc New() *Allocator {\n\treturn &Allocator{}\n}\n\nfunc (a *Allocator) Load(ctx *context.InstrumentorContext) error {\n\tlogger := log.Logger.WithName(\"allocator\")\n\tlogger.V(0).Info(\"Loading allocator\", \"start_addr\",\n\t\tctx.TargetDetails.AllocationDetails.Addr, \"end_addr\", ctx.TargetDetails.AllocationDetails.EndAddr)\n\n\terr := a.mountBpfFS()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (a *Allocator) mountBpfFS() error {\n\t_, err := os.Stat(bpffs.BpfFsPath)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\tif err := os.MkdirAll(bpffs.BpfFsPath, 0755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn unix.Mount(bpffs.BpfFsPath, bpffs.BpfFsPath, \"bpf\", 0, \"\")\n}\n"
  },
  {
    "path": "pkg/instrumentors/api.go",
    "content": "package instrumentors\n\nimport (\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n)\n\ntype Instrumentor interface {\n\tLibraryName() string\n\tFuncNames() []string\n\tLoad(ctx *context.InstrumentorContext) error\n\tRun(eventsChan chan<- *events.Event)\n\tClose()\n}\n"
  },
  {
    "path": "pkg/instrumentors/bpf/github.com/gorilla/mux/bpf/probe.bpf.c",
    "content": "#include \"arguments.h\"\n#include \"span_context.h\"\n#include \"go_context.h\"\n\nchar __license[] SEC(\"license\") = \"Dual MIT/GPL\";\n\n#define MAX_SIZE 100\n#define MAX_CONCURRENT 50\n\nstruct http_request_t {\n    u64 start_time;\n    u64 end_time;\n    char method[MAX_SIZE];\n    char path[MAX_SIZE];\n    struct span_context sc;\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, void*);\n\t__type(value, struct http_request_t);\n\t__uint(max_entries, MAX_CONCURRENT);\n} context_to_http_events SEC(\".maps\");\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);\n} events SEC(\".maps\");\n\n// Injected in init\nvolatile const u64 method_ptr_pos;\nvolatile const u64 url_ptr_pos;\nvolatile const u64 path_ptr_pos;\nvolatile const u64 ctx_ptr_pos;\n\n// This instrumentation attaches uprobe to the following function:\n// func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)\nSEC(\"uprobe/GorillaMux_ServeHTTP\")\nint uprobe_GorillaMux_ServeHTTP(struct pt_regs *ctx) {\n    u64 request_pos = 4;\n    struct http_request_t httpReq = {};\n    httpReq.start_time = bpf_ktime_get_ns();\n\n    // Get request struct\n    void* req_ptr = get_argument(ctx, request_pos);\n\n    // Get method from request\n    void* method_ptr = 0;\n    bpf_probe_read(&method_ptr, sizeof(method_ptr), (void *)(req_ptr+method_ptr_pos));\n    u64 method_len = 0;\n    bpf_probe_read(&method_len, sizeof(method_len), (void *)(req_ptr+(method_ptr_pos+8)));\n    u64 method_size = sizeof(httpReq.method);\n    method_size = method_size < method_len ? method_size : method_len;\n    bpf_probe_read(&httpReq.method, method_size, method_ptr);\n\n    // get path from Request.URL\n    void *url_ptr = 0;\n    bpf_probe_read(&url_ptr, sizeof(url_ptr), (void *)(req_ptr+url_ptr_pos));\n    void* path_ptr = 0;\n    bpf_probe_read(&path_ptr, sizeof(path_ptr), (void *)(url_ptr+path_ptr_pos));\n    u64 path_len = 0;\n    bpf_probe_read(&path_len, sizeof(path_len), (void *)(url_ptr+(path_ptr_pos+8)));\n    u64 path_size = sizeof(httpReq.path);\n    path_size = path_size < path_len ? path_size : path_len;\n    bpf_probe_read(&httpReq.path, path_size, path_ptr);\n\n    // Get Request.ctx\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void *)(req_ptr+ctx_ptr_pos+8));\n\n    // Write event\n    httpReq.sc = generate_span_context();\n    bpf_map_update_elem(&context_to_http_events, &ctx_iface, &httpReq, 0);\n    long res = bpf_map_update_elem(&spans_in_progress, &ctx_iface, &httpReq.sc, 0);\n    return 0;\n}\n\nSEC(\"uprobe/GorillaMux_ServeHTTP\")\nint uprobe_GorillaMux_ServeHTTP_Returns(struct pt_regs *ctx) {\n    u64 request_pos = 4;\n    void* req_ptr = get_argument(ctx, request_pos);\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void *)(req_ptr+ctx_ptr_pos+8));\n\n    void* httpReq_ptr = bpf_map_lookup_elem(&context_to_http_events, &ctx_iface);\n    struct http_request_t httpReq = {};\n    bpf_probe_read(&httpReq, sizeof(httpReq), httpReq_ptr);\n    httpReq.end_time = bpf_ktime_get_ns();\n    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &httpReq, sizeof(httpReq));\n    bpf_map_delete_elem(&context_to_http_events, &ctx_iface);\n    bpf_map_delete_elem(&spans_in_progress, &ctx_iface);\n    return 0;\n}"
  },
  {
    "path": "pkg/instrumentors/bpf/github.com/gorilla/mux/probe.go",
    "content": "package mux\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpffs\"\n\t\"os\"\n\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/perf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.7.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/sys/unix\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c\n\ntype HttpEvent struct {\n\tStartTime   uint64\n\tEndTime     uint64\n\tMethod      [100]byte\n\tPath        [100]byte\n\tSpanContext context.EbpfSpanContext\n}\n\ntype gorillaMuxInstrumentor struct {\n\tbpfObjects   *bpfObjects\n\tuprobe       link.Link\n\treturnProbs  []link.Link\n\teventsReader *perf.Reader\n}\n\nfunc New() *gorillaMuxInstrumentor {\n\treturn &gorillaMuxInstrumentor{}\n}\n\nfunc (g *gorillaMuxInstrumentor) LibraryName() string {\n\treturn \"github.com/gorilla/mux\"\n}\n\nfunc (g *gorillaMuxInstrumentor) FuncNames() []string {\n\treturn []string{\"github.com/gorilla/mux.(*Router).ServeHTTP\"}\n}\n\nfunc (g *gorillaMuxInstrumentor) Load(ctx *context.InstrumentorContext) error {\n\tspec, err := ctx.Injector.Inject(loadBpf, \"go\", ctx.TargetDetails.GoVersion.Original(), []*inject.InjectStructField{\n\t\t{\n\t\t\tVarName:    \"method_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"Method\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"url_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"URL\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"ctx_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"ctx\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"path_ptr_pos\",\n\t\t\tStructName: \"net/url.URL\",\n\t\t\tField:      \"Path\",\n\t\t},\n\t}, false)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.bpfObjects = &bpfObjects{}\n\terr = spec.LoadAndAssign(g.bpfObjects, &ebpf.CollectionOptions{\n\t\tMaps: ebpf.MapOptions{\n\t\t\tPinPath: bpffs.BpfFsPath,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffset, err := ctx.TargetDetails.GetFunctionOffset(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tup, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeGorillaMuxServeHTTP, &link.UprobeOptions{\n\t\tOffset: offset,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.uprobe = up\n\tretOffsets, err := ctx.TargetDetails.GetFunctionReturns(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, ret := range retOffsets {\n\t\tretProbe, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeGorillaMuxServeHTTP_Returns, &link.UprobeOptions{\n\t\t\tOffset: ret,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tg.returnProbs = append(g.returnProbs, retProbe)\n\t}\n\n\trd, err := perf.NewReader(g.bpfObjects.Events, os.Getpagesize())\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.eventsReader = rd\n\n\treturn nil\n}\n\nfunc (g *gorillaMuxInstrumentor) Run(eventsChan chan<- *events.Event) {\n\tlogger := log.Logger.WithName(\"gorilla/mux-instrumentor\")\n\tvar event HttpEvent\n\tfor {\n\t\trecord, err := g.eventsReader.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, perf.ErrClosed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlogger.Error(err, \"error reading from perf reader\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif record.LostSamples != 0 {\n\t\t\tlogger.V(0).Info(\"perf event ring buffer full\", \"dropped\", record.LostSamples)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {\n\t\t\tlogger.Error(err, \"error parsing perf event\")\n\t\t\tcontinue\n\t\t}\n\n\t\teventsChan <- g.convertEvent(&event)\n\t}\n}\n\nfunc (g *gorillaMuxInstrumentor) convertEvent(e *HttpEvent) *events.Event {\n\tmethod := unix.ByteSliceToString(e.Method[:])\n\tpath := unix.ByteSliceToString(e.Path[:])\n\n\tsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\tTraceID:    e.SpanContext.TraceID,\n\t\tSpanID:     e.SpanContext.SpanID,\n\t\tTraceFlags: trace.FlagsSampled,\n\t})\n\n\treturn &events.Event{\n\t\tLibrary:     g.LibraryName(),\n\t\tName:        path,\n\t\tKind:        trace.SpanKindServer,\n\t\tStartTime:   int64(e.StartTime),\n\t\tEndTime:     int64(e.EndTime),\n\t\tSpanContext: &sc,\n\t\tAttributes: []attribute.KeyValue{\n\t\t\tsemconv.HTTPMethodKey.String(method),\n\t\t\tsemconv.HTTPTargetKey.String(path),\n\t\t},\n\t}\n}\n\nfunc (g *gorillaMuxInstrumentor) Close() {\n\tlog.Logger.V(0).Info(\"closing gorilla/mux instrumentor\")\n\tif g.eventsReader != nil {\n\t\tg.eventsReader.Close()\n\t}\n\n\tif g.uprobe != nil {\n\t\tg.uprobe.Close()\n\t}\n\n\tfor _, r := range g.returnProbs {\n\t\tr.Close()\n\t}\n\n\tif g.bpfObjects != nil {\n\t\tg.bpfObjects.Close()\n\t}\n}\n"
  },
  {
    "path": "pkg/instrumentors/bpf/google/golang/org/grpc/bpf/probe.bpf.c",
    "content": "#include \"arguments.h\"\n#include \"go_types.h\"\n#include \"span_context.h\"\n#include \"go_context.h\"\n\nchar __license[] SEC(\"license\") = \"Dual MIT/GPL\";\n\n#define MAX_SIZE 50\n#define MAX_CONCURRENT 50\n#define MAX_HEADERS_BUFF_SIZE 500\n\nstruct grpc_request_t {\n    u64 start_time;\n    u64 end_time;\n    char method[MAX_SIZE];\n    char target[MAX_SIZE];\n    struct span_context sc;\n    struct span_context psc;\n};\n\nstruct hpack_header_field {\n    struct go_string name;\n    struct go_string value;\n    bool sensitive;\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, void*);\n\t__type(value, struct grpc_request_t);\n\t__uint(max_entries, MAX_CONCURRENT);\n} context_to_grpc_events SEC(\".maps\");\n\nstruct headers_buff {\n    unsigned char buff[MAX_HEADERS_BUFF_SIZE];\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);\n\t__type(key, s32);\n\t__type(value, struct headers_buff);\n\t__uint(max_entries, 1);\n} headers_buff_map SEC(\".maps\");\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);\n} events SEC(\".maps\");\n\n// Injected in init\nvolatile const u64 clientconn_target_ptr_pos;\n\n// This instrumentation attaches uprobe to the following function:\n// func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error\nSEC(\"uprobe/ClientConn_Invoke\")\nint uprobe_ClientConn_Invoke(struct pt_regs *ctx) {\n    // positions\n    u64 clientconn_pos = 1;\n    u64 context_pos = 3;\n    u64 method_ptr_pos = 4;\n    u64 method_len_pos = 5;\n\n    struct grpc_request_t grpcReq = {};\n    grpcReq.start_time = bpf_ktime_get_ns();\n\n    // Read Method\n    void* method_ptr = get_argument(ctx, method_ptr_pos);\n    u64 method_len = (u64) get_argument(ctx, method_len_pos);\n    u64 method_size = sizeof(grpcReq.method);\n    method_size = method_size < method_len ? method_size : method_len;\n    bpf_probe_read(&grpcReq.method, method_size, method_ptr);\n\n    // Read ClientConn.Target\n    void* clientconn_ptr = get_argument(ctx, clientconn_pos);\n    void* target_ptr = 0;\n    bpf_probe_read(&target_ptr, sizeof(target_ptr), (void *)(clientconn_ptr+(clientconn_target_ptr_pos)));\n    u64 target_len = 0;\n    bpf_probe_read(&target_len, sizeof(target_len), (void *)(clientconn_ptr+(clientconn_target_ptr_pos+8)));\n    u64 target_size = sizeof(grpcReq.target);\n    target_size = target_size < target_len ? target_size : target_len;\n    bpf_probe_read(&grpcReq.target, target_size, target_ptr);\n\n    // Write event\n    void *context_ptr = get_argument(ctx, context_pos);\n    bpf_map_update_elem(&context_to_grpc_events, &context_ptr, &grpcReq, 0);\n    return 0;\n}\n\nSEC(\"uprobe/ClientConn_Invoke\")\nint uprobe_ClientConn_Invoke_Returns(struct pt_regs *ctx) {\n    u64 context_pos = 3;\n    void *context_ptr = get_argument(ctx, context_pos);\n    void* grpcReq_ptr = bpf_map_lookup_elem(&context_to_grpc_events, &context_ptr);\n    struct grpc_request_t grpcReq = {};\n    bpf_probe_read(&grpcReq, sizeof(grpcReq), grpcReq_ptr);\n\n    grpcReq.end_time = bpf_ktime_get_ns();\n    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &grpcReq, sizeof(grpcReq));\n    bpf_map_delete_elem(&context_to_grpc_events, &context_ptr);\n\n    return 0;\n}\n\n// func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) ([]hpack.HeaderField, error)\nSEC(\"uprobe/Http2Client_createHeaderFields\")\nint uprobe_Http2Client_CreateHeaderFields(struct pt_regs *ctx) {\n    // Read slice\n    s32 context_pointer_pos = 3;\n    struct go_slice slice = {};\n    struct go_slice_user_ptr slice_user_ptr = {};\n    if (is_registers_abi) {\n        slice.array = (void*) GO_PARAM1(ctx);\n        slice.len = (s32) GO_PARAM2(ctx);\n        slice.cap = (s32) GO_PARAM3(ctx);\n        slice_user_ptr.array = (void*) &GO_PARAM1(ctx);\n        slice_user_ptr.len = (void*) &GO_PARAM2(ctx);\n        slice_user_ptr.cap = (void*) &GO_PARAM3(ctx);\n    } else {\n        u64 slice_pointer_pos = 5;\n        s32 slice_len_pos = 6;\n        s32 slice_cap_pos = 7;\n        slice.array = get_argument(ctx, slice_pointer_pos);\n        slice.len = (long) get_argument(ctx, slice_len_pos);\n        slice.cap = (long) get_argument(ctx, slice_cap_pos);\n        bpf_printk(\"slice len: %d, cap: %d\", slice.len, slice.cap);\n        slice_user_ptr.array = (void *)(PT_REGS_SP(ctx)+(slice_pointer_pos*8));\n        slice_user_ptr.len = (void *)(PT_REGS_SP(ctx)+(slice_len_pos*8));\n        slice_user_ptr.cap = (void *)(PT_REGS_SP(ctx)+(slice_cap_pos*8));\n    }\n    char key[11] = \"traceparent\";\n    struct go_string key_str = write_user_go_string(key, sizeof(key));\n    if (key_str.len == 0) {\n        bpf_printk(\"write failed, aborting ebpf probe\");\n        return 0;\n    }\n\n    // Get grpc request struct\n    void *context_ptr = 0;\n    bpf_probe_read(&context_ptr, sizeof(context_ptr), (void *)(PT_REGS_SP(ctx)+(context_pointer_pos*8)));\n    void *parent_ctx = find_context_in_map(context_ptr, &context_to_grpc_events);\n    void* grpcReq_ptr = bpf_map_lookup_elem(&context_to_grpc_events, &parent_ctx);\n    struct grpc_request_t grpcReq = {};\n    bpf_probe_read(&grpcReq, sizeof(grpcReq), grpcReq_ptr);\n\n    // Get parent if exists\n    void *parent_span_ctx = find_context_in_map(context_ptr, &spans_in_progress);\n    if (parent_span_ctx != NULL) {\n        void* psc_ptr = bpf_map_lookup_elem(&spans_in_progress, &parent_span_ctx);\n        bpf_probe_read(&grpcReq.psc, sizeof(grpcReq.psc), psc_ptr);\n        copy_byte_arrays(grpcReq.psc.TraceID, grpcReq.sc.TraceID, TRACE_ID_SIZE);\n        generate_random_bytes(grpcReq.sc.SpanID, SPAN_ID_SIZE);\n    } else {\n        grpcReq.sc = generate_span_context();\n    }\n\n    // Write headers\n    char val[SPAN_CONTEXT_STRING_SIZE];\n    span_context_to_w3c_string(&grpcReq.sc, val);\n    struct go_string val_str = write_user_go_string(val, sizeof(val));\n    struct hpack_header_field hf = {};\n    hf.name = key_str;\n    hf.value = val_str;\n    append_item_to_slice(&slice, &hf, sizeof(hf), &slice_user_ptr, &headers_buff_map);\n    bpf_map_update_elem(&context_to_grpc_events, &parent_ctx, &grpcReq, 0);\n    return 0;\n}"
  },
  {
    "path": "pkg/instrumentors/bpf/google/golang/org/grpc/probe.go",
    "content": "package grpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpffs\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/perf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.4.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/sys/unix\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c\n\ntype GrpcEvent struct {\n\tStartTime         uint64\n\tEndTime           uint64\n\tMethod            [50]byte\n\tTarget            [50]byte\n\tSpanContext       context.EbpfSpanContext\n\tParentSpanContext context.EbpfSpanContext\n}\n\ntype grpcInstrumentor struct {\n\tbpfObjects        *bpfObjects\n\tuprobe            link.Link\n\treturnProbs       []link.Link\n\twriteHeadersProbe []link.Link\n\teventsReader      *perf.Reader\n}\n\nfunc New() *grpcInstrumentor {\n\treturn &grpcInstrumentor{}\n}\n\nfunc (g *grpcInstrumentor) LibraryName() string {\n\treturn \"google.golang.org/grpc\"\n}\n\nfunc (g *grpcInstrumentor) FuncNames() []string {\n\treturn []string{\"google.golang.org/grpc.(*ClientConn).Invoke\",\n\t\t\"google.golang.org/grpc/internal/transport.(*http2Client).createHeaderFields\"}\n}\n\nfunc (g *grpcInstrumentor) Load(ctx *context.InstrumentorContext) error {\n\tlibVersion, exists := ctx.TargetDetails.Libraries[g.LibraryName()]\n\tif !exists {\n\t\tlibVersion = \"\"\n\t}\n\tspec, err := ctx.Injector.Inject(loadBpf, g.LibraryName(), libVersion, []*inject.InjectStructField{\n\t\t{\n\t\t\tVarName:    \"clientconn_target_ptr_pos\",\n\t\t\tStructName: \"google.golang.org/grpc.ClientConn\",\n\t\t\tField:      \"target\",\n\t\t},\n\t}, true)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.bpfObjects = &bpfObjects{}\n\terr = spec.LoadAndAssign(g.bpfObjects, &ebpf.CollectionOptions{\n\t\tMaps: ebpf.MapOptions{\n\t\t\tPinPath: bpffs.BpfFsPath,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffset, err := ctx.TargetDetails.GetFunctionOffset(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tup, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeClientConnInvoke, &link.UprobeOptions{\n\t\tOffset: offset,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.uprobe = up\n\tretOffsets, err := ctx.TargetDetails.GetFunctionReturns(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, ret := range retOffsets {\n\t\tretProbe, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeClientConnInvokeReturns, &link.UprobeOptions{\n\t\t\tOffset: ret,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tg.returnProbs = append(g.returnProbs, retProbe)\n\t}\n\n\trd, err := perf.NewReader(g.bpfObjects.Events, os.Getpagesize())\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.eventsReader = rd\n\n\t// Write headers probe\n\twhOffsets, err := ctx.TargetDetails.GetFunctionReturns(g.FuncNames()[1])\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, whOffset := range whOffsets {\n\t\twhProbe, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeHttp2ClientCreateHeaderFields, &link.UprobeOptions{\n\t\t\tOffset: whOffset,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tg.writeHeadersProbe = append(g.writeHeadersProbe, whProbe)\n\t}\n\n\treturn nil\n}\n\nfunc (g *grpcInstrumentor) Run(eventsChan chan<- *events.Event) {\n\tlogger := log.Logger.WithName(\"grpc-instrumentor\")\n\tvar event GrpcEvent\n\tfor {\n\t\trecord, err := g.eventsReader.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, perf.ErrClosed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlogger.Error(err, \"error reading from perf reader\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif record.LostSamples != 0 {\n\t\t\tlogger.V(0).Info(\"perf event ring buffer full\", \"dropped\", record.LostSamples)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {\n\t\t\tlogger.Error(err, \"error parsing perf event\")\n\t\t\tcontinue\n\t\t}\n\n\t\teventsChan <- g.convertEvent(&event)\n\t}\n}\n\n// According to https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/rpc.md\nfunc (g *grpcInstrumentor) convertEvent(e *GrpcEvent) *events.Event {\n\tmethod := unix.ByteSliceToString(e.Method[:])\n\ttarget := unix.ByteSliceToString(e.Target[:])\n\tvar attrs []attribute.KeyValue\n\n\t// remove port\n\tif parts := strings.Split(target, \":\"); len(parts) > 1 {\n\t\ttarget = parts[0]\n\t\tattrs = append(attrs, semconv.NetPeerPortKey.String(parts[1]))\n\t}\n\n\tattrs = append(attrs, semconv.RPCSystemKey.String(\"grpc\"),\n\t\tsemconv.RPCServiceKey.String(method),\n\t\tsemconv.NetPeerIPKey.String(target),\n\t\tsemconv.NetPeerNameKey.String(target))\n\n\tsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\tTraceID:    e.SpanContext.TraceID,\n\t\tSpanID:     e.SpanContext.SpanID,\n\t\tTraceFlags: trace.FlagsSampled,\n\t})\n\n\tvar pscPtr *trace.SpanContext\n\tif e.ParentSpanContext.TraceID.IsValid() {\n\t\tpsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\t\tTraceID:    e.ParentSpanContext.TraceID,\n\t\t\tSpanID:     e.ParentSpanContext.SpanID,\n\t\t\tTraceFlags: trace.FlagsSampled,\n\t\t\tRemote:     true,\n\t\t})\n\t\tpscPtr = &psc\n\t} else {\n\t\tpscPtr = nil\n\t}\n\n\tlog.Logger.V(0).Info(\"got spancontext\", \"trace_id\", e.SpanContext.TraceID.String(), \"span_id\", e.SpanContext.SpanID.String())\n\treturn &events.Event{\n\t\tLibrary:           g.LibraryName(),\n\t\tName:              method,\n\t\tKind:              trace.SpanKindClient,\n\t\tStartTime:         int64(e.StartTime),\n\t\tEndTime:           int64(e.EndTime),\n\t\tAttributes:        attrs,\n\t\tSpanContext:       &sc,\n\t\tParentSpanContext: pscPtr,\n\t}\n}\n\nfunc (g *grpcInstrumentor) Close() {\n\tlog.Logger.V(0).Info(\"closing gRPC instrumentor\")\n\tif g.eventsReader != nil {\n\t\tg.eventsReader.Close()\n\t}\n\n\tif g.uprobe != nil {\n\t\tg.uprobe.Close()\n\t}\n\n\tfor _, r := range g.returnProbs {\n\t\tr.Close()\n\t}\n\n\tfor _, r := range g.writeHeadersProbe {\n\t\tr.Close()\n\t}\n\n\tif g.bpfObjects != nil {\n\t\tg.bpfObjects.Close()\n\t}\n}\n"
  },
  {
    "path": "pkg/instrumentors/bpf/google/golang/org/grpc/server/bpf/probe.bpf.c",
    "content": "#include \"arguments.h\"\n#include \"go_types.h\"\n#include \"span_context.h\"\n\nchar __license[] SEC(\"license\") = \"Dual MIT/GPL\";\n\n#define MAX_SIZE 100\n#define MAX_CONCURRENT 50\n#define MAX_HEADERS 20\n#define MAX_HEADER_STRING 50\n#define W3C_KEY_LENGTH 11\n#define W3C_VAL_LENGTH 55\n\nstruct grpc_request_t {\n    u64 start_time;\n    u64 end_time;\n    char method[MAX_SIZE];\n    struct span_context sc;\n    struct span_context psc;\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, void*);\n\t__type(value, struct grpc_request_t);\n\t__uint(max_entries, MAX_CONCURRENT);\n} context_to_grpc_events SEC(\".maps\");\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, u32);\n\t__type(value, struct grpc_request_t);\n\t__uint(max_entries, MAX_CONCURRENT);\n} streamid_to_grpc_events SEC(\".maps\");\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);\n} events SEC(\".maps\");\n\nstruct hpack_header_field {\n    struct go_string name;\n    struct go_string value;\n    bool sensitive;\n};\n\n// Injected in init\nvolatile const u64 stream_method_ptr_pos;\nvolatile const u64 frame_fields_pos;\nvolatile const u64 frame_stream_id_pod;\nvolatile const u64 stream_id_pos;\nvolatile const u64 stream_ctx_pos;\n\n// This instrumentation attaches uprobe to the following function:\n// func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) {\nSEC(\"uprobe/server_handleStream\")\nint uprobe_server_handleStream(struct pt_regs *ctx) {\n    u64 stream_pos = 4;\n    void* stream_ptr = get_argument(ctx, stream_pos);\n\n    // Get parent context if exists\n    u32 stream_id = 0;\n    bpf_probe_read(&stream_id, sizeof(stream_id), (void*)(stream_ptr+stream_id_pos));\n    void* grpcReq_ptr = bpf_map_lookup_elem(&streamid_to_grpc_events, &stream_id);\n    struct grpc_request_t grpcReq = {};\n    if (grpcReq_ptr != NULL) {\n        bpf_probe_read(&grpcReq, sizeof(grpcReq), grpcReq_ptr);\n        bpf_map_delete_elem(&streamid_to_grpc_events, &stream_id);\n        copy_byte_arrays(grpcReq.psc.TraceID, grpcReq.sc.TraceID, TRACE_ID_SIZE);\n        generate_random_bytes(grpcReq.sc.SpanID, SPAN_ID_SIZE);\n    } else {\n        grpcReq.sc = generate_span_context();\n    }\n\n    // Set attributes\n    grpcReq.start_time = bpf_ktime_get_ns();\n    void* method_ptr = 0;\n    bpf_probe_read(&method_ptr, sizeof(method_ptr), (void *)(stream_ptr+stream_method_ptr_pos));\n    u64 method_len = 0;\n    bpf_probe_read(&method_len, sizeof(method_len), (void *)(stream_ptr+(stream_method_ptr_pos+8)));\n    u64 method_size = sizeof(grpcReq.method);\n    method_size = method_size < method_len ? method_size : method_len;\n    bpf_probe_read(&grpcReq.method, method_size, method_ptr);\n\n    // Write event\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void*)(stream_ptr+stream_ctx_pos));\n    void *ctx_instance = 0;\n    bpf_probe_read(&ctx_instance, sizeof(ctx_instance), (void*)(ctx_iface+8));\n    bpf_map_update_elem(&context_to_grpc_events, &ctx_instance, &grpcReq, 0);\n    bpf_map_update_elem(&spans_in_progress, &ctx_instance, &grpcReq.sc, 0);\n    return 0;\n}\n\nSEC(\"uprobe/server_handleStream\")\nint uprobe_server_handleStream_Returns(struct pt_regs *ctx) {\n    u64 stream_pos = 4;\n    void* stream_ptr = get_argument(ctx, stream_pos);\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void*)(stream_ptr+stream_ctx_pos));\n    void *ctx_instance = 0;\n    bpf_probe_read(&ctx_instance, sizeof(ctx_instance), (void*)(ctx_iface+8));\n\n    void* grpcReq_ptr = bpf_map_lookup_elem(&context_to_grpc_events, &ctx_instance);\n    struct grpc_request_t grpcReq = {};\n    bpf_probe_read(&grpcReq, sizeof(grpcReq), grpcReq_ptr);\n\n    grpcReq.end_time = bpf_ktime_get_ns();\n    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &grpcReq, sizeof(grpcReq));\n    bpf_map_delete_elem(&context_to_grpc_events, &ctx_instance);\n    bpf_map_delete_elem(&spans_in_progress, &ctx_instance);\n    return 0;\n}\n\n// func (d *decodeState) decodeHeader(frame *http2.MetaHeadersFrame) error\nSEC(\"uprobe/decodeState_decodeHeader\")\nint uprobe_decodeState_decodeHeader(struct pt_regs *ctx) {\n    u64 frame_pos = 2;\n    void* frame_ptr = get_argument(ctx, frame_pos);\n    struct go_slice header_fields = {};\n    bpf_probe_read(&header_fields, sizeof(header_fields), (void *)(frame_ptr+frame_fields_pos));\n    char key[W3C_KEY_LENGTH] = \"traceparent\";\n    for (s32 i = 0; i < MAX_HEADERS; i++) {\n        if (i >=  header_fields.len) {\n            break;\n        }\n        struct hpack_header_field hf = {};\n        long res = bpf_probe_read(&hf, sizeof(hf), (void*)(header_fields.array+(i * sizeof(hf))));\n         if (hf.name.len == W3C_KEY_LENGTH && hf.value.len == W3C_VAL_LENGTH) {\n            char current_key[W3C_KEY_LENGTH];\n            bpf_probe_read(current_key, sizeof(current_key), hf.name.str);\n            if (bpf_memcmp(key, current_key, sizeof(key))) {\n               char val[W3C_VAL_LENGTH];\n               bpf_probe_read(val, W3C_VAL_LENGTH, hf.value.str);\n\n               // Get stream id\n               void* headers_frame = NULL;\n               bpf_probe_read(&headers_frame, sizeof(headers_frame), frame_ptr);\n               u32 stream_id = 0;\n               bpf_probe_read(&stream_id, sizeof(stream_id), (void*)(headers_frame+frame_stream_id_pod));\n               struct grpc_request_t grpcReq = {};\n               w3c_string_to_span_context(val, &grpcReq.psc);\n               bpf_map_update_elem(&streamid_to_grpc_events, &stream_id, &grpcReq, 0);\n            }\n         }\n    }\n\n    return 0;\n}"
  },
  {
    "path": "pkg/instrumentors/bpf/google/golang/org/grpc/server/probe.go",
    "content": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpffs\"\n\t\"os\"\n\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/perf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.7.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/sys/unix\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c\n\ntype GrpcEvent struct {\n\tStartTime         uint64\n\tEndTime           uint64\n\tMethod            [100]byte\n\tSpanContext       context.EbpfSpanContext\n\tParentSpanContext context.EbpfSpanContext\n}\n\ntype grpcServerInstrumentor struct {\n\tbpfObjects   *bpfObjects\n\tuprobe       link.Link\n\treturnProbs  []link.Link\n\theadersProbe link.Link\n\teventsReader *perf.Reader\n}\n\nfunc New() *grpcServerInstrumentor {\n\treturn &grpcServerInstrumentor{}\n}\n\nfunc (g *grpcServerInstrumentor) LibraryName() string {\n\treturn \"google.golang.org/grpc/server\"\n}\n\nfunc (g *grpcServerInstrumentor) FuncNames() []string {\n\treturn []string{\"google.golang.org/grpc.(*Server).handleStream\",\n\t\t\"google.golang.org/grpc/internal/transport.(*http2Server).operateHeaders\"}\n}\n\nfunc (g *grpcServerInstrumentor) Load(ctx *context.InstrumentorContext) error {\n\ttargetLib := \"google.golang.org/grpc\"\n\tlibVersion, exists := ctx.TargetDetails.Libraries[targetLib]\n\tif !exists {\n\t\tlibVersion = \"\"\n\t}\n\tspec, err := ctx.Injector.Inject(loadBpf, \"google.golang.org/grpc\", libVersion, []*inject.InjectStructField{\n\t\t{\n\t\t\tVarName:    \"stream_method_ptr_pos\",\n\t\t\tStructName: \"google.golang.org/grpc/internal/transport.Stream\",\n\t\t\tField:      \"method\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"stream_id_pos\",\n\t\t\tStructName: \"google.golang.org/grpc/internal/transport.Stream\",\n\t\t\tField:      \"id\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"stream_ctx_pos\",\n\t\t\tStructName: \"google.golang.org/grpc/internal/transport.Stream\",\n\t\t\tField:      \"ctx\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"frame_fields_pos\",\n\t\t\tStructName: \"golang.org/x/net/http2.MetaHeadersFrame\",\n\t\t\tField:      \"Fields\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"frame_stream_id_pod\",\n\t\t\tStructName: \"golang.org/x/net/http2.FrameHeader\",\n\t\t\tField:      \"StreamID\",\n\t\t},\n\t}, true)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.bpfObjects = &bpfObjects{}\n\terr = spec.LoadAndAssign(g.bpfObjects, &ebpf.CollectionOptions{\n\t\tMaps: ebpf.MapOptions{\n\t\t\tPinPath: bpffs.BpfFsPath,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffset, err := ctx.TargetDetails.GetFunctionOffset(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tup, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeServerHandleStream, &link.UprobeOptions{\n\t\tOffset: offset,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg.uprobe = up\n\tretOffsets, err := ctx.TargetDetails.GetFunctionReturns(g.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, ret := range retOffsets {\n\t\tretProbe, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeServerHandleStreamReturns, &link.UprobeOptions{\n\t\t\tOffset: ret,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tg.returnProbs = append(g.returnProbs, retProbe)\n\t}\n\n\theaderOffset, err := ctx.TargetDetails.GetFunctionOffset(g.FuncNames()[1])\n\tif err != nil {\n\t\treturn err\n\t}\n\thProbe, err := ctx.Executable.Uprobe(\"\", g.bpfObjects.UprobeDecodeStateDecodeHeader, &link.UprobeOptions{\n\t\tOffset: headerOffset,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.headersProbe = hProbe\n\n\trd, err := perf.NewReader(g.bpfObjects.Events, os.Getpagesize())\n\tif err != nil {\n\t\treturn err\n\t}\n\tg.eventsReader = rd\n\n\treturn nil\n}\n\nfunc (g *grpcServerInstrumentor) Run(eventsChan chan<- *events.Event) {\n\tlogger := log.Logger.WithName(\"grpc-server-instrumentor\")\n\tvar event GrpcEvent\n\tfor {\n\t\trecord, err := g.eventsReader.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, perf.ErrClosed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlogger.Error(err, \"error reading from perf reader\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif record.LostSamples != 0 {\n\t\t\tlogger.V(0).Info(\"perf event ring buffer full\", \"dropped\", record.LostSamples)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {\n\t\t\tlogger.Error(err, \"error parsing perf event\")\n\t\t\tcontinue\n\t\t}\n\n\t\teventsChan <- g.convertEvent(&event)\n\t}\n}\n\nfunc (g *grpcServerInstrumentor) convertEvent(e *GrpcEvent) *events.Event {\n\tmethod := unix.ByteSliceToString(e.Method[:])\n\n\tsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\tTraceID:    e.SpanContext.TraceID,\n\t\tSpanID:     e.SpanContext.SpanID,\n\t\tTraceFlags: trace.FlagsSampled,\n\t})\n\n\tvar pscPtr *trace.SpanContext\n\tif e.ParentSpanContext.TraceID.IsValid() {\n\t\tpsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\t\tTraceID:    e.ParentSpanContext.TraceID,\n\t\t\tSpanID:     e.ParentSpanContext.SpanID,\n\t\t\tTraceFlags: trace.FlagsSampled,\n\t\t\tRemote:     true,\n\t\t})\n\t\tpscPtr = &psc\n\t} else {\n\t\tpscPtr = nil\n\t}\n\n\treturn &events.Event{\n\t\tLibrary:   g.LibraryName(),\n\t\tName:      method,\n\t\tKind:      trace.SpanKindServer,\n\t\tStartTime: int64(e.StartTime),\n\t\tEndTime:   int64(e.EndTime),\n\t\tAttributes: []attribute.KeyValue{\n\t\t\tsemconv.RPCSystemKey.String(\"grpc\"),\n\t\t\tsemconv.RPCServiceKey.String(method),\n\t\t},\n\t\tParentSpanContext: pscPtr,\n\t\tSpanContext:       &sc,\n\t}\n}\n\nfunc (g *grpcServerInstrumentor) Close() {\n\tlog.Logger.V(0).Info(\"closing gRPC server instrumentor\")\n\tif g.eventsReader != nil {\n\t\tg.eventsReader.Close()\n\t}\n\n\tif g.uprobe != nil {\n\t\tg.uprobe.Close()\n\t}\n\n\tfor _, r := range g.returnProbs {\n\t\tr.Close()\n\t}\n\n\tif g.headersProbe != nil {\n\t\tg.headersProbe.Close()\n\t}\n\n\tif g.bpfObjects != nil {\n\t\tg.bpfObjects.Close()\n\t}\n}\n"
  },
  {
    "path": "pkg/instrumentors/bpf/net/http/server/bpf/probe.bpf.c",
    "content": "#include \"arguments.h\"\n#include \"span_context.h\"\n#include \"go_context.h\"\n\nchar __license[] SEC(\"license\") = \"Dual MIT/GPL\";\n\n#define MAX_SIZE 100\n#define MAX_CONCURRENT 50\n\nstruct http_request_t {\n    u64 start_time;\n    u64 end_time;\n    char method[MAX_SIZE];\n    char path[MAX_SIZE];\n    struct span_context sc;\n};\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_HASH);\n\t__type(key, void*);\n\t__type(value, struct http_request_t);\n\t__uint(max_entries, MAX_CONCURRENT);\n} context_to_http_events SEC(\".maps\");\n\nstruct {\n\t__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);\n} events SEC(\".maps\");\n\n// Injected in init\nvolatile const u64 method_ptr_pos;\nvolatile const u64 url_ptr_pos;\nvolatile const u64 path_ptr_pos;\nvolatile const u64 ctx_ptr_pos;\n\n// This instrumentation attaches uprobe to the following function:\n// func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)\nSEC(\"uprobe/ServerMux_ServeHTTP\")\nint uprobe_ServerMux_ServeHTTP(struct pt_regs *ctx) {\n    u64 request_pos = 4;\n    struct http_request_t httpReq = {};\n    httpReq.start_time = bpf_ktime_get_ns();\n\n    // Get request struct\n    void* req_ptr = get_argument(ctx, request_pos);\n\n    // Get method from request\n    void* method_ptr = 0;\n    bpf_probe_read(&method_ptr, sizeof(method_ptr), (void *)(req_ptr+method_ptr_pos));\n    u64 method_len = 0;\n    bpf_probe_read(&method_len, sizeof(method_len), (void *)(req_ptr+(method_ptr_pos+8)));\n    u64 method_size = sizeof(httpReq.method);\n    method_size = method_size < method_len ? method_size : method_len;\n    bpf_probe_read(&httpReq.method, method_size, method_ptr);\n\n    // get path from Request.URL\n    void *url_ptr = 0;\n    bpf_probe_read(&url_ptr, sizeof(url_ptr), (void *)(req_ptr+url_ptr_pos));\n    void* path_ptr = 0;\n    bpf_probe_read(&path_ptr, sizeof(path_ptr), (void *)(url_ptr+path_ptr_pos));\n    u64 path_len = 0;\n    bpf_probe_read(&path_len, sizeof(path_len), (void *)(url_ptr+(path_ptr_pos+8)));\n    u64 path_size = sizeof(httpReq.path);\n    path_size = path_size < path_len ? path_size : path_len;\n    bpf_probe_read(&httpReq.path, path_size, path_ptr);\n\n    // Get Request.ctx\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void *)(req_ptr+ctx_ptr_pos+8));\n\n    // Write event\n    httpReq.sc = generate_span_context();\n    bpf_map_update_elem(&context_to_http_events, &ctx_iface, &httpReq, 0);\n    long res = bpf_map_update_elem(&spans_in_progress, &ctx_iface, &httpReq.sc, 0);\n    return 0;\n}\n\nSEC(\"uprobe/ServerMux_ServeHTTP\")\nint uprobe_ServerMux_ServeHTTP_Returns(struct pt_regs *ctx) {\n    u64 request_pos = 4;\n    void* req_ptr = get_argument_by_stack(ctx, request_pos);\n    void *ctx_iface = 0;\n    bpf_probe_read(&ctx_iface, sizeof(ctx_iface), (void *)(req_ptr+ctx_ptr_pos+8));\n\n    void* httpReq_ptr = bpf_map_lookup_elem(&context_to_http_events, &ctx_iface);\n    struct http_request_t httpReq = {};\n    bpf_probe_read(&httpReq, sizeof(httpReq), httpReq_ptr);\n    httpReq.end_time = bpf_ktime_get_ns();\n    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &httpReq, sizeof(httpReq));\n    bpf_map_delete_elem(&context_to_http_events, &ctx_iface);\n    bpf_map_delete_elem(&spans_in_progress, &ctx_iface);\n    return 0;\n}"
  },
  {
    "path": "pkg/instrumentors/bpf/net/http/server/probe.go",
    "content": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpffs\"\n\t\"os\"\n\n\t\"github.com/cilium/ebpf\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/perf\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.7.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/sys/unix\"\n)\n\n//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags $CFLAGS bpf ./bpf/probe.bpf.c\n\ntype HttpEvent struct {\n\tStartTime   uint64\n\tEndTime     uint64\n\tMethod      [100]byte\n\tPath        [100]byte\n\tSpanContext context.EbpfSpanContext\n}\n\ntype httpServerInstrumentor struct {\n\tbpfObjects   *bpfObjects\n\tuprobe       link.Link\n\treturnProbs  []link.Link\n\teventsReader *perf.Reader\n}\n\nfunc New() *httpServerInstrumentor {\n\treturn &httpServerInstrumentor{}\n}\n\nfunc (h *httpServerInstrumentor) LibraryName() string {\n\treturn \"net/http\"\n}\n\nfunc (h *httpServerInstrumentor) FuncNames() []string {\n\treturn []string{\"net/http.(*ServeMux).ServeHTTP\"}\n}\n\nfunc (h *httpServerInstrumentor) Load(ctx *context.InstrumentorContext) error {\n\tspec, err := ctx.Injector.Inject(loadBpf, \"go\", ctx.TargetDetails.GoVersion.Original(), []*inject.InjectStructField{\n\t\t{\n\t\t\tVarName:    \"method_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"Method\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"url_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"URL\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"ctx_ptr_pos\",\n\t\t\tStructName: \"net/http.Request\",\n\t\t\tField:      \"ctx\",\n\t\t},\n\t\t{\n\t\t\tVarName:    \"path_ptr_pos\",\n\t\t\tStructName: \"net/url.URL\",\n\t\t\tField:      \"Path\",\n\t\t},\n\t}, false)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\th.bpfObjects = &bpfObjects{}\n\terr = spec.LoadAndAssign(h.bpfObjects, &ebpf.CollectionOptions{\n\t\tMaps: ebpf.MapOptions{\n\t\t\tPinPath: bpffs.BpfFsPath,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffset, err := ctx.TargetDetails.GetFunctionOffset(h.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tup, err := ctx.Executable.Uprobe(\"\", h.bpfObjects.UprobeServerMuxServeHTTP, &link.UprobeOptions{\n\t\tOffset: offset,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\th.uprobe = up\n\tretOffsets, err := ctx.TargetDetails.GetFunctionReturns(h.FuncNames()[0])\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, ret := range retOffsets {\n\t\tretProbe, err := ctx.Executable.Uprobe(\"\", h.bpfObjects.UprobeServerMuxServeHTTP_Returns, &link.UprobeOptions{\n\t\t\tOffset: ret,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\th.returnProbs = append(h.returnProbs, retProbe)\n\t}\n\n\trd, err := perf.NewReader(h.bpfObjects.Events, os.Getpagesize())\n\tif err != nil {\n\t\treturn err\n\t}\n\th.eventsReader = rd\n\n\treturn nil\n}\n\nfunc (h *httpServerInstrumentor) Run(eventsChan chan<- *events.Event) {\n\tlogger := log.Logger.WithName(\"net/http-instrumentor\")\n\tvar event HttpEvent\n\tfor {\n\t\trecord, err := h.eventsReader.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, perf.ErrClosed) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlogger.Error(err, \"error reading from perf reader\")\n\t\t\tcontinue\n\t\t}\n\n\t\tif record.LostSamples != 0 {\n\t\t\tlogger.V(0).Info(\"perf event ring buffer full\", \"dropped\", record.LostSamples)\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := binary.Read(bytes.NewBuffer(record.RawSample), binary.LittleEndian, &event); err != nil {\n\t\t\tlogger.Error(err, \"error parsing perf event\")\n\t\t\tcontinue\n\t\t}\n\n\t\teventsChan <- h.convertEvent(&event)\n\t}\n}\n\nfunc (h *httpServerInstrumentor) convertEvent(e *HttpEvent) *events.Event {\n\tmethod := unix.ByteSliceToString(e.Method[:])\n\tpath := unix.ByteSliceToString(e.Path[:])\n\n\tsc := trace.NewSpanContext(trace.SpanContextConfig{\n\t\tTraceID:    e.SpanContext.TraceID,\n\t\tSpanID:     e.SpanContext.SpanID,\n\t\tTraceFlags: trace.FlagsSampled,\n\t})\n\n\treturn &events.Event{\n\t\tLibrary:     h.LibraryName(),\n\t\tName:        path,\n\t\tKind:        trace.SpanKindServer,\n\t\tStartTime:   int64(e.StartTime),\n\t\tEndTime:     int64(e.EndTime),\n\t\tSpanContext: &sc,\n\t\tAttributes: []attribute.KeyValue{\n\t\t\tsemconv.HTTPMethodKey.String(method),\n\t\t\tsemconv.HTTPTargetKey.String(path),\n\t\t},\n\t}\n}\n\nfunc (h *httpServerInstrumentor) Close() {\n\tlog.Logger.V(0).Info(\"closing net/http instrumentor\")\n\tif h.eventsReader != nil {\n\t\th.eventsReader.Close()\n\t}\n\n\tif h.uprobe != nil {\n\t\th.uprobe.Close()\n\t}\n\n\tfor _, r := range h.returnProbs {\n\t\tr.Close()\n\t}\n\n\tif h.bpfObjects != nil {\n\t\th.bpfObjects.Close()\n\t}\n}\n"
  },
  {
    "path": "pkg/instrumentors/bpffs/bpfsfs.go",
    "content": "package bpffs\n\nconst (\n\tBpfFsPath = \"/sys/fs/bpf\"\n)\n"
  },
  {
    "path": "pkg/instrumentors/context/inst_context.go",
    "content": "package context\n\nimport (\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process\"\n)\n\ntype InstrumentorContext struct {\n\tTargetDetails *process.TargetDetails\n\tExecutable    *link.Executable\n\tInjector      *inject.Injector\n}\n"
  },
  {
    "path": "pkg/instrumentors/context/span_context.go",
    "content": "package context\n\nimport \"go.opentelemetry.io/otel/trace\"\n\ntype EbpfSpanContext struct {\n\tTraceID trace.TraceID\n\tSpanID  trace.SpanID\n}\n"
  },
  {
    "path": "pkg/instrumentors/events/event.go",
    "content": "package events\n\nimport (\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\ntype Event struct {\n\tLibrary           string\n\tName              string\n\tAttributes        []attribute.KeyValue\n\tKind              trace.SpanKind\n\tStartTime         int64\n\tEndTime           int64\n\tSpanContext       *trace.SpanContext\n\tParentSpanContext *trace.SpanContext\n}\n"
  },
  {
    "path": "pkg/instrumentors/manager.go",
    "content": "package instrumentors\n\nimport (\n\t\"fmt\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/allocator\"\n\tgorillaMux \"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpf/github.com/gorilla/mux\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpf/google/golang/org/grpc\"\n\tgrpcServer \"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpf/google/golang/org/grpc/server\"\n\thttpServer \"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/bpf/net/http/server\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/opentelemetry\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process\"\n)\n\nvar (\n\tErrNotAllFuncsFound = fmt.Errorf(\"not all functions found for instrumentation\")\n)\n\ntype instrumentorsManager struct {\n\tinstrumentors  map[string]Instrumentor\n\tdone           chan bool\n\tincomingEvents chan *events.Event\n\totelController *opentelemetry.Controller\n\tallocator      *allocator.Allocator\n}\n\nfunc NewManager(otelController *opentelemetry.Controller) (*instrumentorsManager, error) {\n\tm := &instrumentorsManager{\n\t\tinstrumentors:  make(map[string]Instrumentor),\n\t\tdone:           make(chan bool, 1),\n\t\tincomingEvents: make(chan *events.Event),\n\t\totelController: otelController,\n\t\tallocator:      allocator.New(),\n\t}\n\n\terr := registerInstrumentors(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m, nil\n}\n\nfunc (m *instrumentorsManager) registerInstrumentor(instrumentor Instrumentor) error {\n\tif _, exists := m.instrumentors[instrumentor.LibraryName()]; exists {\n\t\treturn fmt.Errorf(\"library %s registered twice, aborting\", instrumentor.LibraryName())\n\t}\n\n\tm.instrumentors[instrumentor.LibraryName()] = instrumentor\n\treturn nil\n}\n\nfunc (m *instrumentorsManager) GetRelevantFuncs() map[string]interface{} {\n\tfuncsMap := make(map[string]interface{})\n\tfor _, i := range m.instrumentors {\n\t\tfor _, f := range i.FuncNames() {\n\t\t\tfuncsMap[f] = nil\n\t\t}\n\t}\n\n\treturn funcsMap\n}\n\nfunc (m *instrumentorsManager) FilterUnusedInstrumentors(target *process.TargetDetails) {\n\texistingFuncMap := make(map[string]interface{})\n\tfor _, f := range target.Functions {\n\t\texistingFuncMap[f.Name] = nil\n\t}\n\n\tfor name, inst := range m.instrumentors {\n\t\tfuncsFound := 0\n\t\tfor _, instF := range inst.FuncNames() {\n\t\t\tif _, exists := existingFuncMap[instF]; exists {\n\t\t\t\tfuncsFound++\n\t\t\t}\n\t\t}\n\n\t\tif funcsFound != len(inst.FuncNames()) {\n\t\t\tif funcsFound > 0 {\n\t\t\t\tlog.Logger.Error(ErrNotAllFuncsFound, \"some of expected functions not found - check instrumented functions\", \"instrumentation_name\", name, \"funcs_found\", funcsFound, \"funcs_expected\", len(inst.FuncNames()))\n\t\t\t}\n\t\t\tdelete(m.instrumentors, name)\n\t\t}\n\t}\n}\n\nfunc registerInstrumentors(m *instrumentorsManager) error {\n\tinsts := []Instrumentor{\n\t\tgrpc.New(),\n\t\tgrpcServer.New(),\n\t\thttpServer.New(),\n\t\tgorillaMux.New(),\n\t}\n\n\tfor _, i := range insts {\n\t\terr := m.registerInstrumentor(i)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/instrumentors/runner.go",
    "content": "package instrumentors\n\nimport (\n\t\"fmt\"\n\t\"github.com/cilium/ebpf/link\"\n\t\"github.com/cilium/ebpf/rlimit\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/inject\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process\"\n)\n\nfunc (m *instrumentorsManager) Run(target *process.TargetDetails) error {\n\tif len(m.instrumentors) == 0 {\n\t\tlog.Logger.V(0).Info(\"there are no avilable instrumentations for target process\")\n\t\treturn nil\n\t}\n\n\terr := m.load(target)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, i := range m.instrumentors {\n\t\tgo i.Run(m.incomingEvents)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-m.done:\n\t\t\tlog.Logger.V(0).Info(\"shutting down all instrumentors due to signal\")\n\t\t\tm.cleanup()\n\t\t\treturn nil\n\t\tcase e := <-m.incomingEvents:\n\t\t\tm.otelController.Trace(e)\n\t\t}\n\t}\n}\n\nfunc (m *instrumentorsManager) load(target *process.TargetDetails) error {\n\t// Allow the current process to lock memory for eBPF resources.\n\tif err := rlimit.RemoveMemlock(); err != nil {\n\t\treturn err\n\t}\n\n\tinjector, err := inject.New(target)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texe, err := link.OpenExecutable(fmt.Sprintf(\"/proc/%d/exe\", target.PID))\n\tif err != nil {\n\t\treturn err\n\t}\n\tctx := &context.InstrumentorContext{\n\t\tTargetDetails: target,\n\t\tExecutable:    exe,\n\t\tInjector:      injector,\n\t}\n\n\tif err := m.allocator.Load(ctx); err != nil {\n\t\tlog.Logger.Error(err, \"failed to load allocator\")\n\t\treturn err\n\t}\n\n\t// Load instrumentors\n\tfor name, i := range m.instrumentors {\n\t\tlog.Logger.V(0).Info(\"loading instrumentor\", \"name\", name)\n\t\terr := i.Load(ctx)\n\t\tif err != nil {\n\t\t\tlog.Logger.Error(err, \"error while loading instrumentors, cleaning up\", \"name\", name)\n\t\t\tm.cleanup()\n\t\t\treturn err\n\t\t}\n\t}\n\n\tlog.Logger.V(0).Info(\"loaded instrumentors to memory\", \"total_instrumentors\", len(m.instrumentors))\n\treturn nil\n}\n\nfunc (m *instrumentorsManager) cleanup() {\n\tclose(m.incomingEvents)\n\tfor _, i := range m.instrumentors {\n\t\ti.Close()\n\t}\n}\n\nfunc (m *instrumentorsManager) Close() {\n\tm.done <- true\n}\n"
  },
  {
    "path": "pkg/log/logger.go",
    "content": "package log\n\nimport (\n\t\"github.com/go-logr/logr\"\n\t\"github.com/go-logr/zapr\"\n\t\"go.uber.org/zap\"\n)\n\nvar Logger logr.Logger\n\nfunc Init() error {\n\tzapLog, err := zap.NewProduction()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tLogger = zapr.NewLogger(zapLog)\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/opentelemetry/controller.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/prometheus/procfs\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc\"\n\t\"go.opentelemetry.io/otel/exporters/stdout/stdouttrace\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\tsdktrace \"go.opentelemetry.io/otel/sdk/trace\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.7.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/sys/unix\"\n\t\"google.golang.org/grpc\"\n)\n\nconst (\n\totelEndpointEnvVar    = \"OTEL_EXPORTER_OTLP_ENDPOINT\"\n\totelServiceNameEnvVar = \"OTEL_SERVICE_NAME\"\n)\n\ntype Controller struct {\n\ttracerProvider trace.TracerProvider\n\ttracersMap     map[string]trace.Tracer\n\tbootTime       int64\n}\n\nfunc (c *Controller) getTracer(libName string) trace.Tracer {\n\tt, exists := c.tracersMap[libName]\n\tif exists {\n\t\treturn t\n\t}\n\n\tnewTracer := c.tracerProvider.Tracer(libName)\n\tc.tracersMap[libName] = newTracer\n\treturn newTracer\n}\n\nfunc (c *Controller) Trace(event *events.Event) {\n\tlog.Logger.V(0).Info(\"got event\", \"attrs\", event.Attributes)\n\tctx := context.Background()\n\n\tif event.SpanContext == nil {\n\t\tlog.Logger.V(0).Info(\"got event without context - dropping\")\n\t\treturn\n\t}\n\n\t// TODO: handle remote parent\n\tif event.ParentSpanContext != nil {\n\t\tctx = trace.ContextWithSpanContext(ctx, *event.ParentSpanContext)\n\t}\n\n\tctx = ContextWithEbpfEvent(ctx, *event)\n\t_, span := c.getTracer(event.Library).\n\t\tStart(ctx, event.Name,\n\t\t\ttrace.WithAttributes(event.Attributes...),\n\t\t\ttrace.WithSpanKind(event.Kind),\n\t\t\ttrace.WithTimestamp(c.convertTime(event.StartTime)))\n\tspan.End(trace.WithTimestamp(c.convertTime(event.EndTime)))\n}\n\nfunc (c *Controller) convertTime(t int64) time.Time {\n\treturn time.Unix(0, c.bootTime+t)\n}\n\nfunc NewStdoutController() (*Controller, error) {\n\ttraceExporter, err := stdouttrace.New()\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbsp := sdktrace.NewBatchSpanProcessor(traceExporter)\n\ttracerProvider := sdktrace.NewTracerProvider(\n\t\tsdktrace.WithSampler(sdktrace.AlwaysSample()),\n\t\tsdktrace.WithSpanProcessor(bsp),\n\t\tsdktrace.WithIDGenerator(NewEbpfSourceIDGenerator()),\n\t)\n\n\tbt, err := estimateBootTimeOffset()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Controller{\n\t\ttracerProvider: tracerProvider,\n\t\ttracersMap:     make(map[string]trace.Tracer),\n\t\tbootTime:       bt,\n\t}, nil\n}\n\nfunc NewController() (*Controller, error) {\n\tendpoint, exists := os.LookupEnv(otelEndpointEnvVar)\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"%s env var must be set\", otelEndpointEnvVar)\n\t}\n\n\tserviceName, exists := os.LookupEnv(otelServiceNameEnvVar)\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"%s env var must be set\", otelServiceNameEnvVar)\n\t}\n\n\tctx := context.Background()\n\tres, err := resource.New(ctx,\n\t\tresource.WithAttributes(\n\t\t\tsemconv.ServiceNameKey.String(serviceName),\n\t\t\tsemconv.TelemetrySDKLanguageGo,\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Logger.V(0).Info(\"Establishing connection to OpenTelemetry collector ...\")\n\ttimeoutContext, cancel := context.WithTimeout(ctx, time.Second*10)\n\tdefer cancel()\n\tconn, err := grpc.DialContext(timeoutContext, endpoint, grpc.WithInsecure(), grpc.WithBlock())\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"unable to connect to OpenTelemetry collector\", \"addr\", endpoint)\n\t\treturn nil, err\n\t}\n\n\ttraceExporter, err := otlptracegrpc.New(ctx,\n\t\totlptracegrpc.WithGRPCConn(conn),\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbsp := sdktrace.NewBatchSpanProcessor(traceExporter)\n\ttracerProvider := sdktrace.NewTracerProvider(\n\t\tsdktrace.WithSampler(sdktrace.AlwaysSample()),\n\t\tsdktrace.WithResource(res),\n\t\tsdktrace.WithSpanProcessor(bsp),\n\t\tsdktrace.WithIDGenerator(NewEbpfSourceIDGenerator()),\n\t)\n\n\tbt, err := estimateBootTimeOffset()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Controller{\n\t\ttracerProvider: tracerProvider,\n\t\ttracersMap:     make(map[string]trace.Tracer),\n\t\tbootTime:       bt,\n\t}, nil\n}\n\nfunc getBootTime() (*time.Time, error) {\n\tfs, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstat, err := fs.Stat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tboot := time.Unix(int64(stat.BootTime), 0)\n\treturn &boot, nil\n}\n\nfunc getBootTimeSyscall() (int64, error) {\n\tvar ts unix.Timespec\n\terr := unix.ClockGettime(unix.CLOCK_MONOTONIC, &ts)\n\tnow := time.Now().UnixNano()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"could not get boot time: %s\", err)\n\t}\n\n\treturn now - unix.TimespecToNsec(ts), nil\n}\n\nfunc estimateBootTimeOffset() (bootTimeOffset int64, err error) {\n\t// The datapath is currently using ktime_get_boot_ns for the pcap timestamp,\n\t// which corresponds to CLOCK_BOOTTIME. To be able to convert the the\n\t// CLOCK_BOOTTIME to CLOCK_REALTIME (i.e. a unix timestamp).\n\n\t// There can be an arbitrary amount of time between the execution of\n\t// time.Now() and unix.ClockGettime() below, especially under scheduler\n\t// pressure during program startup. To reduce the error introduced by these\n\t// delays, we pin the current Go routine to its OS thread and measure the\n\t// clocks multiple times, taking only the smallest observed difference\n\t// between the two values (which implies the smallest possible delay\n\t// between the two snapshots).\n\tvar minDiff int64 = 1<<63 - 1\n\testimationRounds := 25\n\truntime.LockOSThread()\n\tdefer runtime.UnlockOSThread()\n\tfor round := 0; round < estimationRounds; round++ {\n\t\tvar bootTimespec unix.Timespec\n\n\t\t// Ideally we would use __vdso_clock_gettime for both clocks here,\n\t\t// to have as little overhead as possible.\n\t\t// time.Now() will actually use VDSO on Go 1.9+, but calling\n\t\t// unix.ClockGettime to obtain CLOCK_BOOTTIME is a regular system call\n\t\t// for now.\n\t\tunixTime := time.Now()\n\t\terr = unix.ClockGettime(unix.CLOCK_BOOTTIME, &bootTimespec)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\toffset := unixTime.UnixNano() - bootTimespec.Nano()\n\t\tdiff := offset\n\t\tif diff < 0 {\n\t\t\tdiff = -diff\n\t\t}\n\n\t\tif diff < minDiff {\n\t\t\tminDiff = diff\n\t\t\tbootTimeOffset = offset\n\t\t}\n\t}\n\n\treturn bootTimeOffset, nil\n}\n"
  },
  {
    "path": "pkg/opentelemetry/id_generator.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/instrumentors/events\"\n\t\"go.opentelemetry.io/otel/trace\"\n)\n\ntype eBPFSourceIDGenerator struct{}\n\ntype ebpfEventKey struct{}\n\nfunc NewEbpfSourceIDGenerator() *eBPFSourceIDGenerator {\n\treturn &eBPFSourceIDGenerator{}\n}\n\nfunc ContextWithEbpfEvent(ctx context.Context, event events.Event) context.Context {\n\treturn context.WithValue(ctx, ebpfEventKey{}, event)\n}\n\nfunc EventFromContext(ctx context.Context) *events.Event {\n\tval := ctx.Value(ebpfEventKey{})\n\tif val == nil {\n\t\treturn nil\n\t}\n\n\tevent, ok := val.(events.Event)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\treturn &event\n}\n\nfunc (e *eBPFSourceIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) {\n\tevent := EventFromContext(ctx)\n\tif event == nil || event.SpanContext == nil {\n\t\treturn trace.TraceID{}, trace.SpanID{}\n\t}\n\t\n\treturn event.SpanContext.TraceID(), event.SpanContext.SpanID()\n}\n\nfunc (e *eBPFSourceIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID {\n\tevent := EventFromContext(ctx)\n\tif event == nil {\n\t\treturn trace.SpanID{}\n\t}\n\n\treturn event.SpanContext.SpanID()\n}\n"
  },
  {
    "path": "pkg/process/analyze.go",
    "content": "package process\n\nimport (\n\t\"debug/elf\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/hashicorp/go-version\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/process/ptrace\"\n\t\"os\"\n)\n\nconst (\n\tmapSize = 4096 * 6 * 1024\n)\n\ntype TargetDetails struct {\n\tPID               int\n\tFunctions         []*Func\n\tGoVersion         *version.Version\n\tLibraries         map[string]string\n\tAllocationDetails *AllocationDetails\n}\n\ntype AllocationDetails struct {\n\tAddr    uint64\n\tEndAddr uint64\n}\n\ntype Func struct {\n\tName          string\n\tOffset        uint64\n\tReturnOffsets []uint64\n}\n\nfunc (t *TargetDetails) IsRegistersABI() bool {\n\tregAbiMinVersion, _ := version.NewVersion(\"1.17\")\n\treturn t.GoVersion.GreaterThanOrEqual(regAbiMinVersion)\n}\n\nfunc (t *TargetDetails) GetFunctionOffset(name string) (uint64, error) {\n\tfor _, f := range t.Functions {\n\t\tif f.Name == name {\n\t\t\treturn f.Offset, nil\n\t\t}\n\t}\n\n\treturn 0, fmt.Errorf(\"could not find offset for function %s\", name)\n}\n\nfunc (t *TargetDetails) GetFunctionReturns(name string) ([]uint64, error) {\n\tfor _, f := range t.Functions {\n\t\tif f.Name == name {\n\t\t\treturn f.ReturnOffsets, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"could not find returns for function %s\", name)\n}\n\nfunc (a *processAnalyzer) remoteMmap(pid int, mapSize uint64) (uint64, error) {\n\tprogram, err := ptrace.Trace(pid, log.Logger)\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"Failed to attach ptrace\", \"pid\", pid)\n\t\treturn 0, err\n\t}\n\n\tdefer func() {\n\t\tlog.Logger.V(0).Info(\"Detaching from process\", \"pid\", pid)\n\t\terr := program.Detach()\n\t\tif err != nil {\n\t\t\tlog.Logger.Error(err, \"Failed to detach ptrace\", \"pid\", pid)\n\t\t}\n\t}()\n\tfd := -1\n\taddr, err := program.Mmap(mapSize, uint64(fd))\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"Failed to mmap\", \"pid\", pid)\n\t\treturn 0, err\n\t}\n\n\treturn addr, nil\n}\n\nfunc (a *processAnalyzer) Analyze(pid int, relevantFuncs map[string]interface{}) (*TargetDetails, error) {\n\tresult := &TargetDetails{\n\t\tPID: pid,\n\t}\n\n\tf, err := os.Open(fmt.Sprintf(\"/proc/%d/exe\", pid))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close()\n\telfF, err := elf.NewFile(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgoVersion, modules, err := a.getModuleDetails(elfF)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult.GoVersion = goVersion\n\tresult.Libraries = modules\n\n\taddr, err := a.remoteMmap(pid, mapSize)\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"Failed to mmap\")\n\t\treturn nil, err\n\t}\n\tlog.Logger.V(0).Info(\"mmaped remote memory\", \"start_addr\", fmt.Sprintf(\"%X\", addr),\n\t\t\"end_addr\", fmt.Sprintf(\"%X\", addr+mapSize))\n\n\tresult.AllocationDetails = &AllocationDetails{\n\t\tAddr:    addr,\n\t\tEndAddr: addr + mapSize,\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfuncs, err := findFunctions(elfF, relevantFuncs)\n\tif err != nil {\n\t\tlog.Logger.Error(err, \"Failed to find functions\")\n\t\treturn nil, err\n\t}\n\n\tresult.Functions = funcs\n\treturn result, nil\n}\n\nfunc findFunctions(elfF *elf.File, relevantFuncs map[string]interface{}) ([]*Func, error) {\n\tresult, err := FindFunctionsUnStripped(elfF, relevantFuncs)\n\tif err != nil {\n\t\tif errors.Is(err, elf.ErrNoSymbols) {\n\t\t\tlog.Logger.V(0).Info(\"No symbols found in binary, trying to find functions using .gosymtab\")\n\t\t\treturn FindFunctionsStripped(elfF, relevantFuncs)\n\t\t}\n\t\treturn nil, err\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/process/args.go",
    "content": "package process\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"os\"\n)\n\nconst (\n\tExePathEnvVar = \"OTEL_TARGET_EXE\"\n)\n\ntype TargetArgs struct {\n\tExePath string\n\tStdout  bool\n}\n\nfunc (t *TargetArgs) Validate() error {\n\tif t.ExePath == \"\" {\n\t\treturn errors.New(\"target binary path not specified\")\n\t}\n\n\treturn nil\n}\n\nfunc ParseTargetArgs() *TargetArgs {\n\tresult := &TargetArgs{}\n\n\tprintHelp := flag.Bool(\"help\", false, \"\")\n\totelStdout := flag.Bool(\"stdout\", false, \"if true, print otel telemetry to stdout (use for local development or debugging)\")\n\n\tflag.Parse()\n\n\tif *printHelp {\n\t\tflag.PrintDefaults()\n\t\tos.Exit(0)\n\t}\n\n\tresult.Stdout = *otelStdout\n\n\tval, exists := os.LookupEnv(ExePathEnvVar)\n\tif exists {\n\t\tresult.ExePath = val\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "pkg/process/discover.go",
    "content": "package process\n\nimport (\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/errors\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tinitExeName = \"/odigos/init\"\n)\n\ntype processAnalyzer struct {\n\tdone          chan bool\n\tpidTickerChan <-chan time.Time\n}\n\nfunc NewAnalyzer() *processAnalyzer {\n\treturn &processAnalyzer{\n\t\tdone:          make(chan bool, 1),\n\t\tpidTickerChan: time.NewTicker(2 * time.Second).C,\n\t}\n}\n\nfunc (a *processAnalyzer) DiscoverProcessID(target *TargetArgs) (int, error) {\n\tfor {\n\t\tselect {\n\t\tcase <-a.done:\n\t\t\tlog.Logger.V(0).Info(\"stopping process id discovery due to kill signal\")\n\t\t\treturn 0, errors.ErrInterrupted\n\t\tcase <-a.pidTickerChan:\n\t\t\tpid, err := a.findProcessID(target)\n\t\t\tif err != nil {\n\t\t\t\tif err == errors.ErrProcessNotFound {\n\t\t\t\t\tlog.Logger.V(0).Info(\"process not found yet, trying again soon\", \"exe_path\", target.ExePath)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Logger.Error(err, \"error while searching for process\", \"exe_path\", target.ExePath)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlog.Logger.V(0).Info(\"found process\", \"pid\", pid)\n\t\t\t\treturn pid, nil\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (a *processAnalyzer) findProcessID(target *TargetArgs) (int, error) {\n\tproc, err := os.Open(\"/proc\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tfor {\n\t\tdirs, err := proc.Readdir(15)\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tfor _, di := range dirs {\n\t\t\tif !di.IsDir() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdname := di.Name()\n\t\t\tif dname[0] < '0' || dname[0] > '9' {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tpid, err := strconv.Atoi(dname)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\n\t\t\texeName, err := os.Readlink(path.Join(\"/proc\", dname, \"exe\"))\n\t\t\tif err != nil {\n\t\t\t\t// Read link may fail if target process runs not as root\n\t\t\t\tcmdLine, err := ioutil.ReadFile(path.Join(\"/proc\", dname, \"cmdline\"))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\n\t\t\t\tif !strings.Contains(string(cmdLine), initExeName) && strings.Contains(string(cmdLine), target.ExePath) {\n\t\t\t\t\treturn pid, nil\n\t\t\t\t}\n\t\t\t} else if exeName == target.ExePath {\n\t\t\t\treturn pid, nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0, errors.ErrProcessNotFound\n}\n\nfunc (a *processAnalyzer) Close() {\n\ta.done <- true\n}\n"
  },
  {
    "path": "pkg/process/funcs_nonstripped.go",
    "content": "package process\n\nimport (\n\t\"debug/elf\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n)\n\nfunc FindFunctionsUnStripped(elfF *elf.File, relevantFuncs map[string]interface{}) ([]*Func, error) {\n\tsymbols, err := elfF.Symbols()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result []*Func\n\tfor _, f := range symbols {\n\t\tif _, exists := relevantFuncs[f.Name]; exists {\n\t\t\toffset, err := getFuncOffsetUnstripped(elfF, f)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturns, err := findFuncReturnsUnstripped(elfF, f, offset)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tlog.Logger.V(0).Info(\"found relevant function for instrumentation\", \"function\", f.Name, \"returns\", len(returns))\n\t\t\tfunction := &Func{\n\t\t\t\tName:          f.Name,\n\t\t\t\tOffset:        offset,\n\t\t\t\tReturnOffsets: returns,\n\t\t\t}\n\n\t\t\tresult = append(result, function)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc getFuncOffsetUnstripped(f *elf.File, symbol elf.Symbol) (uint64, error) {\n\tvar sections []*elf.Section\n\n\tfor i := range f.Sections {\n\t\tif f.Sections[i].Flags == elf.SHF_ALLOC+elf.SHF_EXECINSTR {\n\t\t\tsections = append(sections, f.Sections[i])\n\t\t}\n\t}\n\n\tif len(sections) == 0 {\n\t\treturn 0, fmt.Errorf(\"function %q not found in file\", symbol)\n\t}\n\n\tvar execSection *elf.Section\n\tfor m := range sections {\n\t\tsectionStart := sections[m].Addr\n\t\tsectionEnd := sectionStart + sections[m].Size\n\t\tif symbol.Value >= sectionStart && symbol.Value < sectionEnd {\n\t\t\texecSection = sections[m]\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif execSection == nil {\n\t\treturn 0, errors.New(\"could not find symbol in executable sections of binary\")\n\t}\n\n\treturn uint64(symbol.Value - execSection.Addr + execSection.Offset), nil\n}\n\nfunc findFuncReturnsUnstripped(elfFile *elf.File, sym elf.Symbol, functionOffset uint64) ([]uint64, error) {\n\ttextSection := elfFile.Section(\".text\")\n\tif textSection == nil {\n\t\treturn nil, errors.New(\"could not find .text section in binary\")\n\t}\n\n\tlowPC := sym.Value\n\thighPC := lowPC + sym.Size\n\toffset := lowPC - textSection.Addr\n\tbuf := make([]byte, int(highPC-lowPC))\n\n\treadBytes, err := textSection.ReadAt(buf, int64(offset))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not read text section: %w\", err)\n\t}\n\tdata := buf[:readBytes]\n\tinstructionIndices, err := findRetInstructions(data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error while scanning instructions: %w\", err)\n\t}\n\n\t// Add the function lowPC to each index to obtain the actual locations\n\tnewLocations := make([]uint64, len(instructionIndices))\n\tfor i, instructionIndex := range instructionIndices {\n\t\tnewLocations[i] = instructionIndex + functionOffset\n\t}\n\n\treturn newLocations, nil\n}\n"
  },
  {
    "path": "pkg/process/funcs_stripped.go",
    "content": "package process\n\nimport (\n\t\"debug/elf\"\n\t\"debug/gosym\"\n\t\"fmt\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n)\n\nfunc FindFunctionsStripped(elfF *elf.File, relevantFuncs map[string]interface{}) ([]*Func, error) {\n\tvar pclndat []byte\n\tif sec := elfF.Section(\".gopclntab\"); sec != nil {\n\t\tvar err error\n\t\tpclndat, err = sec.Data()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsec := elfF.Section(\".gosymtab\")\n\tif sec == nil {\n\t\treturn nil, fmt.Errorf(\"%s section not found in target binary, make sure this is a Go application\", \".gosymtab\")\n\t}\n\tsymTabRaw, err := sec.Data()\n\tpcln := gosym.NewLineTable(pclndat, elfF.Section(\".text\").Addr)\n\tsymTab, err := gosym.NewTable(symTabRaw, pcln)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result []*Func\n\tfor _, f := range symTab.Funcs {\n\t\tif _, exists := relevantFuncs[f.Name]; exists {\n\t\t\tstart, returns, err := findFuncOffsetStripped(&f, elfF)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tlog.Logger.V(0).Info(\"found relevant function for instrumentation\", \"function\", f.Name, \"returns\", len(returns))\n\t\t\tfunction := &Func{\n\t\t\t\tName:          f.Name,\n\t\t\t\tOffset:        start,\n\t\t\t\tReturnOffsets: returns,\n\t\t\t}\n\n\t\t\tresult = append(result, function)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc findFuncOffsetStripped(f *gosym.Func, elfF *elf.File) (uint64, []uint64, error) {\n\toff := f.Value\n\tfor _, prog := range elfF.Progs {\n\t\tif prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// For more info on this calculation: stackoverflow.com/a/40249502\n\t\tif prog.Vaddr <= f.Value && f.Value < (prog.Vaddr+prog.Memsz) {\n\t\t\toff = f.Value - prog.Vaddr + prog.Off\n\n\t\t\tfuncLen := f.End - f.Entry\n\t\t\tdata := make([]byte, funcLen)\n\t\t\t_, err := prog.ReadAt(data, int64(f.Value-prog.Vaddr))\n\t\t\tif err != nil {\n\t\t\t\tlog.Logger.Error(err, \"error while finding function return\")\n\t\t\t\treturn 0, nil, err\n\t\t\t}\n\n\t\t\tinstructionIndices, err := findRetInstructions(data)\n\t\t\tif err != nil {\n\t\t\t\tlog.Logger.Error(err, \"error while finding function returns\")\n\t\t\t\treturn 0, nil, err\n\t\t\t}\n\n\t\t\tnewLocations := make([]uint64, len(instructionIndices))\n\t\t\tfor i, instructionIndex := range instructionIndices {\n\t\t\t\tnewLocations[i] = instructionIndex + off\n\t\t\t}\n\n\t\t\treturn off, newLocations, nil\n\t\t}\n\n\t}\n\n\treturn 0, nil, fmt.Errorf(\"prog not found\")\n}\n"
  },
  {
    "path": "pkg/process/module.go",
    "content": "package process\n\nimport (\n\t\"bytes\"\n\t\"debug/elf\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/hashicorp/go-version\"\n\t\"github.com/keyval-dev/opentelemetry-go-instrumentation/pkg/log\"\n\t\"strings\"\n)\n\n// The build info blob left by the linker is identified by\n// a 16-byte header, consisting of buildInfoMagic (14 bytes),\n// the binary's pointer size (1 byte),\n// and whether the binary is big endian (1 byte).\nvar buildInfoMagic = []byte(\"\\xff Go buildinf:\")\nvar errNotGoExe = errors.New(\"not a Go executable\")\n\nfunc (a *processAnalyzer) getModuleDetails(f *elf.File) (*version.Version, map[string]string, error) {\n\tgoVersion, modules, err := getGoDetails(f)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tv, err := parseGoVersion(goVersion)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tlog.Logger.V(1).Info(\"go version detected\", \"version\", goVersion)\n\tmodsMap := parseModules(modules)\n\treturn v, modsMap, nil\n}\n\nfunc parseGoVersion(vers string) (*version.Version, error) {\n\tvers = strings.ReplaceAll(vers, \"go\", \"\")\n\treturn version.NewVersion(vers)\n}\n\nfunc getGoDetails(f *elf.File) (string, string, error) {\n\t// Read the first 64kB of text to find the build info blob.\n\ttext := dataStart(f)\n\tdata, err := readData(f, text, 64*1024)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tconst (\n\t\tbuildInfoAlign = 16\n\t\tbuildInfoSize  = 32\n\t)\n\tfor {\n\t\ti := bytes.Index(data, buildInfoMagic)\n\t\tif i < 0 || len(data)-i < buildInfoSize {\n\t\t\treturn \"\", \"\", errNotGoExe\n\t\t}\n\t\tif i%buildInfoAlign == 0 && len(data)-i >= buildInfoSize {\n\t\t\tdata = data[i:]\n\t\t\tbreak\n\t\t}\n\t\tdata = data[(i+buildInfoAlign-1)&^buildInfoAlign:]\n\t}\n\n\t// Decode the blob.\n\t// The first 14 bytes are buildInfoMagic.\n\t// The next two bytes indicate pointer size in bytes (4 or 8) and endianness\n\t// (0 for little, 1 for big).\n\t// Two virtual addresses to Go strings follow that: runtime.buildVersion,\n\t// and runtime.modinfo.\n\t// On 32-bit platforms, the last 8 bytes are unused.\n\t// If the endianness has the 2 bit set, then the pointers are zero\n\t// and the 32-byte header is followed by varint-prefixed string data\n\t// for the two string values we care about.\n\tptrSize := int(data[14])\n\tvar vers, mod string\n\tif data[15]&2 != 0 {\n\t\tvers, data = decodeString(data[32:])\n\t\tmod, data = decodeString(data)\n\t} else {\n\t\tbigEndian := data[15] != 0\n\t\tvar bo binary.ByteOrder\n\t\tif bigEndian {\n\t\t\tbo = binary.BigEndian\n\t\t} else {\n\t\t\tbo = binary.LittleEndian\n\t\t}\n\t\tvar readPtr func([]byte) uint64\n\t\tif ptrSize == 4 {\n\t\t\treadPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) }\n\t\t} else {\n\t\t\treadPtr = bo.Uint64\n\t\t}\n\t\tvers = readString(f, ptrSize, readPtr, readPtr(data[16:]))\n\t\tmod = readString(f, ptrSize, readPtr, readPtr(data[16+ptrSize:]))\n\t}\n\tif vers == \"\" {\n\t\treturn \"\", \"\", errNotGoExe\n\t}\n\tif len(mod) >= 33 && mod[len(mod)-17] == '\\n' {\n\t\t// Strip module framing: sentinel strings delimiting the module info.\n\t\t// These are cmd/go/internal/modload.infoStart and infoEnd.\n\t\tmod = mod[16 : len(mod)-16]\n\t} else {\n\t\tmod = \"\"\n\t}\n\n\treturn vers, mod, nil\n}\n\nfunc dataStart(f *elf.File) uint64 {\n\tfor _, s := range f.Sections {\n\t\tif s.Name == \".go.buildinfo\" {\n\t\t\treturn s.Addr\n\t\t}\n\t}\n\tfor _, p := range f.Progs {\n\t\tif p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W {\n\t\t\treturn p.Vaddr\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc readData(f *elf.File, addr, size uint64) ([]byte, error) {\n\tfor _, prog := range f.Progs {\n\t\tif prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {\n\t\t\tn := prog.Vaddr + prog.Filesz - addr\n\t\t\tif n > size {\n\t\t\t\tn = size\n\t\t\t}\n\t\t\tdata := make([]byte, n)\n\t\t\t_, err := prog.ReadAt(data, int64(addr-prog.Vaddr))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn data, nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"address not mapped\")\n}\n\n// readString returns the string at address addr in the executable x.\nfunc readString(f *elf.File, ptrSize int, readPtr func([]byte) uint64, addr uint64) string {\n\thdr, err := readData(f, addr, uint64(2*ptrSize))\n\tif err != nil || len(hdr) < 2*ptrSize {\n\t\treturn \"\"\n\t}\n\tdataAddr := readPtr(hdr)\n\tdataLen := readPtr(hdr[ptrSize:])\n\tdata, err := readData(f, dataAddr, dataLen)\n\tif err != nil || uint64(len(data)) < dataLen {\n\t\treturn \"\"\n\t}\n\treturn string(data)\n}\n\nfunc parseModules(mod string) map[string]string {\n\tlines := strings.Split(mod, \"\\n\")\n\tresult := make(map[string]string)\n\tfor _, line := range lines {\n\t\tparts := strings.Fields(line)\n\t\tif len(parts) > 1 {\n\t\t\tmodType := parts[0]\n\t\t\tmodPackage := parts[1]\n\t\t\tif modType == \"dep\" {\n\t\t\t\tv := \"\"\n\t\t\t\tif len(parts) > 2 {\n\t\t\t\t\tv = parts[2]\n\t\t\t\t}\n\n\t\t\t\tresult[modPackage] = v\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc decodeString(data []byte) (s string, rest []byte) {\n\tu, n := binary.Uvarint(data)\n\tif n <= 0 || u >= uint64(len(data)-n) {\n\t\treturn \"\", nil\n\t}\n\treturn string(data[n : uint64(n)+u]), data[uint64(n)+u:]\n}\n"
  },
  {
    "path": "pkg/process/ptrace/cwrapper_linux.go",
    "content": "//go:build cgo\n\npackage ptrace\n\n/*\n#define _GNU_SOURCE\n#include <sys/wait.h>\n#include <sys/uio.h>\n#include <errno.h>\n*/\nimport \"C\"\n\nfunc waitpid(pid int) int {\n\treturn int(C.waitpid(C.int(pid), nil, C.__WALL))\n}\n"
  },
  {
    "path": "pkg/process/ptrace/ptrace_linux.go",
    "content": "package ptrace\n\nimport (\n\t\"fmt\"\n\t\"github.com/go-logr/logr\"\n\t\"github.com/pkg/errors\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n)\n\nconst waitPidErrorMessage = \"waitpid ret value: %d\"\n\n// If it's on 64-bit platform, `^uintptr(0)` will get a 64-bit number full of one.\n// After shifting right for 63-bit, only 1 will be left. Than we got 8 here.\n// If it's on 32-bit platform, After shifting nothing will be left. Than we got 4 here.\nconst ptrSize = 4 << uintptr(^uintptr(0)>>63)\n\nvar threadRetryLimit = 10\n\n// TracedProgram is a program traced by ptrace\ntype TracedProgram struct {\n\tpid  int\n\ttids []int\n\n\tbackupRegs *syscall.PtraceRegs\n\tbackupCode []byte\n\n\tlogger logr.Logger\n}\n\n// Pid return the pid of traced program\nfunc (p *TracedProgram) Pid() int {\n\treturn p.pid\n}\n\nfunc waitPid(pid int) error {\n\tret := waitpid(pid)\n\tif ret == pid {\n\t\treturn nil\n\t}\n\n\treturn errors.Errorf(waitPidErrorMessage, ret)\n}\n\n// Trace ptrace all threads of a process\nfunc Trace(pid int, logger logr.Logger) (*TracedProgram, error) {\n\ttraceSuccess := false\n\n\ttidMap := make(map[int]bool)\n\tretryCount := make(map[int]int)\n\n\t// iterate over the thread group, until it doens't change\n\t//\n\t// we have tried several ways to ensure that we have stopped all the tasks:\n\t// 1. iterating over and over again to make sure all of them are tracee\n\t// 2. send `SIGSTOP` signal\n\t// ...\n\t// only the first way finally worked for every situations\n\tfor {\n\t\tthreads, err := os.ReadDir(fmt.Sprintf(\"/proc/%d/task\", pid))\n\t\tif err != nil {\n\t\t\treturn nil, errors.WithStack(err)\n\t\t}\n\n\t\t// judge whether `threads` is a subset of `tidMap`\n\t\tsubset := true\n\n\t\ttids := make(map[int]bool)\n\t\tfor _, thread := range threads {\n\t\t\ttid64, err := strconv.ParseInt(thread.Name(), 10, 32)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.WithStack(err)\n\t\t\t}\n\t\t\ttid := int(tid64)\n\n\t\t\t_, ok := tidMap[tid]\n\t\t\tif ok {\n\t\t\t\ttids[tid] = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tsubset = false\n\n\t\t\terr = syscall.PtraceAttach(tid)\n\t\t\tif err != nil {\n\t\t\t\t_, ok := retryCount[tid]\n\t\t\t\tif !ok {\n\t\t\t\t\tretryCount[tid] = 1\n\t\t\t\t} else {\n\t\t\t\t\tretryCount[tid]++\n\t\t\t\t}\n\t\t\t\tif retryCount[tid] < threadRetryLimit {\n\t\t\t\t\tlogger.Info(\"retry attaching thread\", \"tid\", tid, \"retryCount\", retryCount[tid], \"limit\", threadRetryLimit)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif !strings.Contains(err.Error(), \"no such process\") {\n\t\t\t\t\treturn nil, errors.WithStack(err)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\tif !traceSuccess {\n\t\t\t\t\terr = syscall.PtraceDetach(tid)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif !strings.Contains(err.Error(), \"no such process\") {\n\t\t\t\t\t\t\tlogger.Error(err, \"detach failed\", \"tid\", tid)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\terr = waitPid(tid)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.WithStack(err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"attach successfully\", \"tid\", tid)\n\t\t\ttids[tid] = true\n\t\t\ttidMap[tid] = true\n\t\t}\n\n\t\tif subset {\n\t\t\ttidMap = tids\n\t\t\tbreak\n\t\t}\n\t}\n\n\tvar tids []int\n\tfor key := range tidMap {\n\t\ttids = append(tids, key)\n\t}\n\n\tprogram := &TracedProgram{\n\t\tpid:        pid,\n\t\ttids:       tids,\n\t\tbackupRegs: &syscall.PtraceRegs{},\n\t\tbackupCode: make([]byte, syscallInstrSize),\n\t\tlogger:     logger,\n\t}\n\n\ttraceSuccess = true\n\n\treturn program, nil\n}\n\n// Detach detaches from all threads of the processes\nfunc (p *TracedProgram) Detach() error {\n\tfor _, tid := range p.tids {\n\t\terr := syscall.PtraceDetach(tid)\n\n\t\tif err != nil {\n\t\t\tif !strings.Contains(err.Error(), \"no such process\") {\n\t\t\t\treturn errors.WithStack(err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Protect will backup regs and rip into fields\nfunc (p *TracedProgram) Protect() error {\n\terr := getRegs(p.pid, p.backupRegs)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\t_, err = syscall.PtracePeekData(p.pid, getIp(p.backupRegs), p.backupCode)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\treturn nil\n}\n\n// Restore will restore regs and rip from fields\nfunc (p *TracedProgram) Restore() error {\n\terr := setRegs(p.pid, p.backupRegs)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\t_, err = syscall.PtracePokeData(p.pid, getIp(p.backupRegs), p.backupCode)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\treturn nil\n}\n\n// Wait waits until the process stops\nfunc (p *TracedProgram) Wait() error {\n\t_, err := syscall.Wait4(p.pid, nil, 0, nil)\n\treturn err\n}\n\n// Step moves one step forward\nfunc (p *TracedProgram) Step() error {\n\terr := syscall.PtraceSingleStep(p.pid)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\n\treturn p.Wait()\n}\n\n// Mmap runs mmap syscall\nfunc (p *TracedProgram) Mmap(length uint64, fd uint64) (uint64, error) {\n\treturn p.Syscall(syscall.SYS_MMAP, 0, length, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_ANON|syscall.MAP_PRIVATE|syscall.MAP_POPULATE, fd, 0)\n}\n"
  },
  {
    "path": "pkg/process/ptrace/ptrace_linux_amd64.go",
    "content": "package ptrace\n\nimport (\n\t\"encoding/binary\"\n\t\"syscall\"\n\n\t\"github.com/pkg/errors\"\n)\n\nconst syscallInstrSize = 2\n\nfunc getIp(regs *syscall.PtraceRegs) uintptr {\n\treturn uintptr(regs.Rip)\n}\n\nfunc getRegs(pid int, regsout *syscall.PtraceRegs) error {\n\terr := syscall.PtraceGetRegs(pid, regsout)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"get registers of process %d\", pid)\n\t}\n\n\treturn nil\n}\n\nfunc setRegs(pid int, regs *syscall.PtraceRegs) error {\n\terr := syscall.PtraceSetRegs(pid, regs)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"set registers of process %d\", pid)\n\t}\n\n\treturn nil\n}\n\n// Syscall runs a syscall at main thread of process\nfunc (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) {\n\t// save the original registers and the current instructions\n\terr := p.Protect()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar regs syscall.PtraceRegs\n\n\terr = getRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\t// set the registers according to the syscall convention. Learn more about\n\t// it in `man 2 syscall`. In x86_64 the syscall nr is stored in rax\n\t// register, and the arguments are stored in rdi, rsi, rdx, r10, r8, r9 in\n\t// order\n\tregs.Rax = number\n\tfor index, arg := range args {\n\t\t// All these registers are hard coded for x86 platform\n\t\tif index == 0 {\n\t\t\tregs.Rdi = arg\n\t\t} else if index == 1 {\n\t\t\tregs.Rsi = arg\n\t\t} else if index == 2 {\n\t\t\tregs.Rdx = arg\n\t\t} else if index == 3 {\n\t\t\tregs.R10 = arg\n\t\t} else if index == 4 {\n\t\t\tregs.R8 = arg\n\t\t} else if index == 5 {\n\t\t\tregs.R9 = arg\n\t\t} else {\n\t\t\treturn 0, errors.New(\"too many arguments for a syscall\")\n\t\t}\n\t}\n\terr = setRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tinstruction := make([]byte, syscallInstrSize)\n\tip := getIp(p.backupRegs)\n\n\t// set the current instruction (the ip register points to) to the `syscall`\n\t// instruction. In x86_64, the `syscall` instruction is 0x050f.\n\tbinary.LittleEndian.PutUint16(instruction, 0x050f)\n\t_, err = syscall.PtracePokeData(p.pid, ip, instruction)\n\tif err != nil {\n\t\treturn 0, errors.Wrapf(err, \"writing data %v to %x\", instruction, ip)\n\t}\n\n\t// run one instruction, and stop\n\terr = p.Step()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// read registers, the return value of syscall is stored inside rax register\n\terr = getRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// restore the state saved at beginning.\n\treturn regs.Rax, p.Restore()\n}\n"
  },
  {
    "path": "pkg/process/ptrace/ptrace_linux_arm64.go",
    "content": "package ptrace\n\nimport (\n\t\"encoding/binary\"\n\t\"syscall\"\n\n\t\"github.com/pkg/errors\"\n\t\"golang.org/x/sys/unix\"\n)\n\nvar endian = binary.LittleEndian\n\nconst syscallInstrSize = 4\n\n// see kernel source /include/uapi/linux/elf.h\nconst nrPRStatus = 1\n\nfunc getIp(regs *syscall.PtraceRegs) uintptr {\n\treturn uintptr(regs.Pc)\n}\n\nfunc getRegs(pid int, regsout *syscall.PtraceRegs) error {\n\terr := unix.PtraceGetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regsout))\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"get registers of process %d\", pid)\n\t}\n\treturn nil\n}\n\nfunc setRegs(pid int, regs *syscall.PtraceRegs) error {\n\terr := unix.PtraceSetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regs))\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"set registers of process %d\", pid)\n\t}\n\treturn nil\n}\n\n// Syscall runs a syscall at main thread of process\nfunc (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) {\n\t// save the original registers and the current instructions\n\terr := p.Protect()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar regs syscall.PtraceRegs\n\n\terr = getRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\t// set the registers according to the syscall convention. Learn more about\n\t// it in `man 2 syscall`. In aarch64 the syscall nr is stored in w8, and the\n\t// arguments are stored in x0, x1, x2, x3, x4, x5 in order\n\tregs.Regs[8] = number\n\tfor index, arg := range args {\n\t\t// All these registers are hard coded for x86 platform\n\t\tif index > 6 {\n\t\t\treturn 0, errors.New(\"too many arguments for a syscall\")\n\t\t} else {\n\t\t\tregs.Regs[index] = arg\n\t\t}\n\t}\n\terr = setRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tinstruction := make([]byte, syscallInstrSize)\n\tip := getIp(p.backupRegs)\n\n\t// most aarch64 devices are little endian\n\t// 0xd4000001 is `svc #0` to call the system call\n\tendian.PutUint32(instruction, 0xd4000001)\n\t_, err = syscall.PtracePokeData(p.pid, ip, instruction)\n\tif err != nil {\n\t\treturn 0, errors.Wrapf(err, \"writing data %v to %x\", instruction, ip)\n\t}\n\n\t// run one instruction, and stop\n\terr = p.Step()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// read registers, the return value of syscall is stored inside x0 register\n\terr = getRegs(p.pid, &regs)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn regs.Regs[0], p.Restore()\n}\n"
  },
  {
    "path": "pkg/process/ret_linux_amd64.go",
    "content": "package process\n\nimport (\n\t\"fmt\"\n\t\"golang.org/x/arch/x86/x86asm\"\n)\n\nfunc findRetInstructions(data []byte) ([]uint64, error) {\n\tvar returnOffsets []uint64\n\tindex := 0\n\tfor index < len(data) {\n\t\tinstruction, err := x86asm.Decode(data[index:], 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode x64 instruction at offset %d: %w\", index, err)\n\t\t}\n\n\t\tif instruction.Op == x86asm.RET {\n\t\t\treturnOffsets = append(returnOffsets, uint64(index))\n\t\t}\n\n\t\tindex += instruction.Len\n\t}\n\n\treturn returnOffsets, nil\n}\n"
  },
  {
    "path": "pkg/process/ret_linux_arm64.go",
    "content": "package process\n\nimport (\n\t\"golang.org/x/arch/arm64/arm64asm\"\n)\n\nconst (\n\t// In ARM64 each instruction is 4 bytes in length\n\tarmInstructionSize = 4\n)\n\nfunc findRetInstructions(data []byte) ([]uint64, error) {\n\tvar returnOffsets []uint64\n\tindex := 0\n\tfor index < len(data) {\n\t\tinstruction, err := arm64asm.Decode(data[index:])\n\t\tif err == nil && instruction.Op == arm64asm.RET {\n\t\t\treturnOffsets = append(returnOffsets, uint64(index))\n\t\t}\n\n\t\tindex += armInstructionSize\n\t}\n\n\treturn returnOffsets, nil\n}\n"
  }
]