├── .cargo └── config.toml ├── .codespellignore ├── .codespellrc ├── .dockerignore ├── .github ├── CODEOWNERS ├── renovate.json5 └── workflows │ ├── codeql.yml │ ├── codespell.yml │ ├── env │ └── action.yml │ ├── fossa.yml │ ├── ossf-scorecard.yml │ ├── push-docker-image.yml │ └── unit-test-on-pull-request.yml ├── .gitignore ├── .golangci.yml ├── AUTHORS.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── LICENSES ├── github.com │ ├── cespare │ │ └── xxhash │ │ │ └── v2 │ │ │ └── LICENSE.txt │ ├── cilium │ │ └── ebpf │ │ │ └── LICENSE │ ├── elastic │ │ ├── go-freelru │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ └── go-perf │ │ │ └── LICENSE │ ├── go-logr │ │ ├── logr │ │ │ └── LICENSE │ │ └── stdr │ │ │ └── LICENSE │ ├── gogo │ │ └── protobuf │ │ │ └── LICENSE │ ├── google │ │ └── uuid │ │ │ └── LICENSE │ ├── josharian │ │ └── native │ │ │ └── license │ ├── jsimonetti │ │ └── rtnetlink │ │ │ └── LICENSE.md │ ├── json-iterator │ │ └── go │ │ │ └── LICENSE │ ├── klauspost │ │ └── cpuid │ │ │ └── v2 │ │ │ └── LICENSE │ ├── mdlayher │ │ ├── netlink │ │ │ └── LICENSE.md │ │ └── socket │ │ │ └── LICENSE.md │ ├── minio │ │ └── sha256-simd │ │ │ └── LICENSE │ ├── modern-go │ │ ├── concurrent │ │ │ └── LICENSE │ │ └── reflect2 │ │ │ └── LICENSE │ ├── peterbourgon │ │ └── ff │ │ │ └── v3 │ │ │ └── LICENSE │ ├── sirupsen │ │ └── logrus │ │ │ └── LICENSE │ ├── tklauser │ │ └── numcpus │ │ │ └── LICENSE │ └── zeebo │ │ └── xxh3 │ │ └── LICENSE ├── go.opentelemetry.io │ ├── auto │ │ └── sdk │ │ │ └── LICENSE │ ├── collector │ │ ├── consumer │ │ │ ├── LICENSE │ │ │ └── xconsumer │ │ │ │ └── LICENSE │ │ └── pdata │ │ │ ├── LICENSE │ │ │ └── pprofile │ │ │ └── LICENSE │ ├── ebpf-profiler │ │ └── LICENSE │ └── otel │ │ ├── LICENSE │ │ ├── metric │ │ └── LICENSE │ │ └── trace │ │ └── LICENSE ├── go.uber.org │ └── multierr │ │ └── LICENSE.txt ├── golang.org │ └── x │ │ ├── arch │ │ └── LICENSE │ │ ├── exp │ │ └── constraints │ │ │ └── LICENSE │ │ ├── net │ │ └── LICENSE │ │ ├── sync │ │ └── errgroup │ │ │ └── LICENSE │ │ ├── sys │ │ └── unix │ │ │ └── LICENSE │ │ └── text │ │ └── LICENSE ├── google.golang.org │ ├── genproto │ │ └── googleapis │ │ │ └── rpc │ │ │ └── status │ │ │ └── LICENSE │ ├── grpc │ │ ├── LICENSE │ │ └── NOTICE.txt │ └── protobuf │ │ └── LICENSE └── zyantific │ └── zydis │ └── LICENSE ├── Makefile ├── README.md ├── armhelpers └── arm_helpers.go ├── asm └── amd │ ├── insn.go │ ├── insn_test.go │ └── regs_state.go ├── cli_flags.go ├── collector ├── factory.go ├── factory_test.go └── internal │ └── controller.go ├── design-docs ├── 00000-example-docs │ ├── 02612-process-manager-fileid-pid-split │ │ └── README.md │ ├── 04359-remove-bpf-hashing │ │ ├── README.md │ │ ├── known-trace-metrics.png │ │ ├── memcpy-cost.png │ │ ├── option2-ghidra-workload.png │ │ ├── option2-idle-workload.png │ │ ├── trace-pipe-reworked.drawio.svg │ │ └── trace-pipe.drawio.svg │ └── README.md ├── 00000-templates │ ├── long-form-design-doc-template.md │ └── short-form-design-doc-template.md ├── 00001-off-cpu-profiling │ └── README.md ├── 159-collector-api │ └── README.md └── README.md ├── doc ├── KNOWN_KERNEL_LIMITATIONS.md ├── bpf-trace.drawio.svg ├── gopclntab.md ├── network-trace.drawio.svg └── trace-pipe.drawio.svg ├── go.mod ├── go.sum ├── host └── host.go ├── internal ├── controller │ ├── config.go │ └── controller.go └── helpers │ ├── address.go │ ├── kernel.go │ └── namespaces.go ├── interpreter ├── apmint │ ├── apmint.go │ └── socket.go ├── dotnet │ ├── cachingreader.go │ ├── data.go │ ├── dotnet.go │ ├── instance.go │ ├── method.go │ ├── nativereader.go │ ├── nativereader_test.go │ ├── nibblereader.go │ ├── nibblereader_test.go │ └── pe.go ├── go │ ├── go.go │ ├── go_amd64.go │ └── go_arm64.go ├── hotspot │ ├── data.go │ ├── demangle.go │ ├── demangle_test.go │ ├── hotspot.go │ ├── instance.go │ ├── instance_test.go │ ├── method.go │ ├── recordingreader.go │ ├── recordingreader_test.go │ ├── stubs.go │ ├── unsigned5.go │ └── unsigned5_test.go ├── instancestubs.go ├── loaderinfo.go ├── nodev8 │ └── v8.go ├── perl │ ├── data.go │ ├── instance.go │ └── perl.go ├── php │ ├── decode_amd64.c │ ├── decode_amd64.go │ ├── decode_amd64.h │ ├── decode_arm64.go │ ├── instance.go │ ├── opcache.go │ ├── php.go │ └── php_test.go ├── python │ ├── decode.go │ ├── decode_test.go │ ├── python.go │ └── python_test.go ├── ruby │ └── ruby.go └── types.go ├── legal ├── add-non-go.sh └── non-go-dependencies.json ├── libpf ├── address.go ├── apm.go ├── basehash │ ├── basehash.go │ ├── hash128.go │ └── hash128_test.go ├── cgroupv2.go ├── convenience.go ├── convenience_test.go ├── fileid.go ├── fileid_test.go ├── frameid.go ├── frameid_test.go ├── frametype.go ├── frametype_test.go ├── generics.go ├── hash │ ├── hash.go │ └── hash_test.go ├── interpretertype.go ├── libpf.go ├── libpf_test.go ├── pfelf │ ├── addressmapper.go │ ├── addressmapper_test.go │ ├── elfopener.go │ ├── file.go │ ├── file_test.go │ ├── internal │ │ └── mmap │ │ │ ├── mmap.go │ │ │ └── mmap_test.go │ ├── pfelf.go │ ├── pfelf_test.go │ ├── reference.go │ └── testdata │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── fixed-address.c │ │ ├── fixed-address.ld │ │ ├── gotest.go │ │ └── test.c ├── pid.go ├── readatbuf │ ├── readatbuf.go │ └── readatbuf_test.go ├── symbol.go ├── trace.go ├── tracehash.go ├── tracehash_test.go └── xsync │ ├── doc.go │ ├── once.go │ ├── once_test.go │ ├── rwlock.go │ └── rwlock_test.go ├── lpm ├── lpm.go └── lpm_test.go ├── maccess ├── maccess.go ├── maccess_amd64.go ├── maccess_amd64_test.go ├── maccess_arm64.go └── maccess_arm64_test.go ├── main.go ├── metrics ├── doc.go ├── genids │ └── main.go ├── ids.go ├── metrics.go ├── metrics.json ├── metrics_test.go └── types.go ├── nativeunwind ├── elfunwindinfo │ ├── README.md │ ├── elfehframe.go │ ├── elfehframe_aarch64.go │ ├── elfehframe_test.go │ ├── elfehframe_x86.go │ ├── elfgopclntab.go │ ├── elfgopclntab_test.go │ ├── stackdeltaextraction.go │ ├── stackdeltaextraction_test.go │ ├── stackdeltaprovider.go │ └── testdata │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── helloworld.go │ │ ├── schrodinger-libpython3.8.so.1.0 │ │ └── test.so ├── stackdeltaprovider.go └── stackdeltatypes │ └── stackdeltatypes.go ├── nopanicslicereader ├── nopanicslicereader.go └── nopanicslicereader_test.go ├── pacmask ├── pacmask_arm64.go ├── pacmask_arm64.s └── pacmask_other.go ├── periodiccaller ├── periodiccaller.go └── periodiccaller_test.go ├── proc ├── proc.go ├── proc_test.go └── testdata │ ├── kallsyms │ ├── kallsyms_0 │ └── kallsyms_invalid ├── process ├── coredump.go ├── debug.go ├── debug_amd64.go ├── debug_arm64.go ├── process.go ├── process_test.go └── types.go ├── processmanager ├── ebpf │ ├── asyncupdate.go │ ├── asyncupdate_integration_test.go │ ├── ebpf.go │ ├── ebpf_integration_test.go │ ├── ebpf_test.go │ └── types.go ├── execinfomanager │ └── manager.go ├── helpers.go ├── manager.go ├── manager_test.go ├── processinfo.go ├── synthdeltas.go ├── synthdeltas_arm64.go ├── synthdeltas_other.go ├── synthdeltas_test.go ├── testdata │ └── vdso.arch64.withframe └── types.go ├── remotememory ├── remotememory.go └── remotememory_test.go ├── reporter ├── base_reporter.go ├── collector_reporter.go ├── collector_reporter_test.go ├── config.go ├── iface.go ├── internal │ └── pdata │ │ ├── generate.go │ │ ├── generate_test.go │ │ └── pdata.go ├── otlp_reporter.go ├── runloop.go ├── samples │ ├── attrmgr.go │ ├── attrmgr_test.go │ └── samples.go ├── testdata │ ├── .gitignore │ ├── Makefile │ └── test.c ├── times.go └── util.go ├── rlimit └── rlimit.go ├── rust-crates ├── README.md ├── symb-proto │ ├── README.md │ └── symbfile.proto ├── symblib-capi │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── c │ │ ├── Makefile │ │ ├── demo.c │ │ └── symblib.h │ ├── go │ │ ├── Makefile │ │ └── main.go │ └── src │ │ ├── ffislice.rs │ │ ├── ffistr.rs │ │ ├── gosym.rs │ │ ├── lib.rs │ │ ├── pointresolver.rs │ │ ├── rangeextr.rs │ │ ├── retpadextr.rs │ │ └── status.rs └── symblib │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── src │ ├── covmap.rs │ ├── dbglog.rs │ ├── demangle.rs │ ├── disas.rs │ ├── dwarf.rs │ ├── fileid.rs │ ├── gosym │ │ ├── errors.rs │ │ ├── mod.rs │ │ └── raw │ │ │ ├── mod.rs │ │ │ ├── reader.rs │ │ │ ├── regions.rs │ │ │ ├── structs.rs │ │ │ └── types.rs │ ├── lib.rs │ ├── objfile.rs │ ├── retpads.rs │ ├── symbconv │ │ ├── dwarf │ │ │ ├── mod.rs │ │ │ └── rangetree.rs │ │ ├── go.rs │ │ ├── mod.rs │ │ ├── multi.rs │ │ └── obj.rs │ └── symbfile │ │ ├── mod.rs │ │ ├── proto.rs │ │ ├── read.rs │ │ ├── records.rs │ │ ├── strdedup.rs │ │ └── write.rs │ └── testdata │ ├── Makefile │ ├── README.md │ ├── go-1.20.14 │ ├── go-1.22.12 │ ├── go-1.24.0 │ ├── go.mod │ ├── inline │ ├── inline-big-fake-compressed-dwarf │ ├── inline-compressed-dwarf │ ├── inline-compressed-dwarf-zstd │ ├── inline-no-tco │ ├── inline-no-tco.ranges.symbfile │ ├── inline-split-dwarf │ ├── inline-split-dwarf.dwp │ ├── inline.c │ └── main.go ├── stringutil ├── stringutil.go └── stringutil_test.go ├── successfailurecounter ├── successfailurecounter.go └── successfailurecounter_test.go ├── support ├── .gitignore ├── PYTHON_LINENO_RECOVERY_README.md ├── README.md ├── debugtracer_amd64.go ├── debugtracer_arm64.go ├── debugtracer_dummy.go ├── ebpf │ ├── .clang-format │ ├── LICENSE │ ├── Makefile │ ├── bloat-o-meter │ ├── bpf_map.h │ ├── bpfdefs.h │ ├── dotnet_tracer.ebpf.c │ ├── errors.h │ ├── extmaps.h │ ├── frametypes.h │ ├── hotspot_tracer.ebpf.c │ ├── integration_test.ebpf.c │ ├── interpreter_dispatcher.ebpf.c │ ├── kernel.h │ ├── native_stack_trace.ebpf.c │ ├── off_cpu.ebpf.c │ ├── perl_tracer.ebpf.c │ ├── php_tracer.ebpf.c │ ├── print_instruction_count.sh │ ├── python_tracer.ebpf.c │ ├── ruby_tracer.ebpf.c │ ├── sched_monitor.ebpf.c │ ├── stackdeltatypes.h │ ├── system_config.ebpf.c │ ├── tracemgmt.h │ ├── tracer.ebpf.release.amd64 │ ├── tracer.ebpf.release.arm64 │ ├── tsd.h │ ├── types.h │ ├── v8_tracer.ebpf.c │ └── v8_tracer.h ├── generate.sh ├── helper.go ├── run-tests.sh ├── support.go ├── support_amd64.go ├── support_arm64.go ├── support_others.go ├── support_test.go ├── tests │ └── main_thread_exit.c ├── types.go └── types_def.go ├── target ├── aarch64-unknown-linux-musl │ └── release │ │ └── libsymblib_capi.a └── x86_64-unknown-linux-musl │ └── release │ └── libsymblib_capi.a ├── testsupport ├── io.go └── testfiles.go ├── times ├── ktime.go └── times.go ├── tools ├── coredump │ ├── .gitignore │ ├── README.md │ ├── analyze.go │ ├── clean.go │ ├── coredump.go │ ├── coredump_test.go │ ├── ebpfcode.go │ ├── ebpfcontext.go │ ├── ebpfhelpers.go │ ├── ebpfmaps.go │ ├── exportmodule.go │ ├── gdb.go │ ├── json.go │ ├── main.go │ ├── modulestore │ │ ├── id.go │ │ ├── reader.go │ │ ├── store.go │ │ └── util.go │ ├── new.go │ ├── rebase.go │ ├── storecoredump.go │ ├── testdata │ │ ├── amd64 │ │ │ ├── .gitkeep │ │ │ ├── brokenstack.json │ │ │ ├── dotnet7-helloworld-alpine.json │ │ │ ├── gcloud_sdk_502.0.0_slim_3.11.9_clang_18.1.8.json │ │ │ ├── glibc-signalframe.json │ │ │ ├── go-1.24.1-hello.json.json │ │ │ ├── graalvm-native.json │ │ │ ├── java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256msg2.json │ │ │ ├── java11.25812.json │ │ │ ├── java12.20153.json │ │ │ ├── java13.11581.json │ │ │ ├── java14.3576.json │ │ │ ├── java16.43723.json │ │ │ ├── java16.43768.json │ │ │ ├── java20-helloworld.json │ │ │ ├── java23-helloworld.json │ │ │ ├── java7.10958.json │ │ │ ├── java8.10171.json │ │ │ ├── musl-signalframe.json │ │ │ ├── node1610.26681.json │ │ │ ├── node1617-inlining.json │ │ │ ├── node1815-baseline.json │ │ │ ├── node1816-async.json │ │ │ ├── node189-inlining.json │ │ │ ├── node211.json │ │ │ ├── openssl-gcm.json │ │ │ ├── openssl.14327.json │ │ │ ├── perl528.14.json │ │ │ ├── perl528.151.json │ │ │ ├── perl528.206.json │ │ │ ├── perl534.220234.json │ │ │ ├── perl536-a.json │ │ │ ├── perl536-helloWorld.json │ │ │ ├── php-8.2.10-prime.json │ │ │ ├── php-8.3.6-prime.json │ │ │ ├── php74.7893.json │ │ │ ├── php8.103871.json │ │ │ ├── pyenv_3.12.9_gcc_13.3.0.json │ │ │ ├── pyenv_3.13.2_clang_21.0.0.json │ │ │ ├── python3.12-expat-debian-unstable.json │ │ │ ├── python310.stringbench.20086.json │ │ │ ├── python310.stringbench.2576.json │ │ │ ├── python311-expat.json │ │ │ ├── python311.50282.json │ │ │ ├── python37.26320.json │ │ │ ├── ruby-2.7.8p225-loop.json │ │ │ ├── ruby-3.0.4p208-loop.json │ │ │ ├── ruby-3.0.6p216-loop.json │ │ │ ├── ruby-3.1.0p0-loop.json │ │ │ ├── ruby-3.1.4p223-loop.json │ │ │ ├── ruby-3.2.2-loop.json │ │ │ ├── ruby25.20836.json │ │ │ ├── ruby25.benchmark-serialization.10811.json │ │ │ ├── ruby27.2186.json │ │ │ ├── ruby30.253432.json │ │ │ ├── stackalign.4040.json │ │ │ └── stackdeltas.11629.json │ │ └── arm64 │ │ │ ├── .gitkeep │ │ │ ├── brokenstack.json │ │ │ ├── glibc-signal-arm.json │ │ │ ├── go.symbhack.readheader.json │ │ │ ├── hello.3345.hello3.body.stp-after-bl.json │ │ │ ├── hello.3345.hello4.epi.add.json │ │ │ ├── hello.3345.hello4.epi.ret.json │ │ │ ├── hello.3345.hello5.body.adrp.json │ │ │ ├── hello.3345.hello5.epi.add.json │ │ │ ├── hello.3345.hello5.epi.ret.json │ │ │ ├── hello.3345.hello5.pro.add.json │ │ │ ├── hello.3345.hello5.pro.stp.json │ │ │ ├── hello.3345.hello5.pro.str.json │ │ │ ├── hello.3345.hello5.pro.stur.json │ │ │ ├── hello.3345.hello5.pro.sub.json │ │ │ ├── hello.3345.leaf.ret.json │ │ │ ├── hello.345.hello5.body.add.json │ │ │ ├── java-17.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h.json │ │ │ ├── java-21.ShaShenanigans.StubRoutines.sha256_implCompressMB.sha256h2.json │ │ │ ├── java.PrologueEpilogue.epi.add-sp-sp.377026.json │ │ │ ├── java.PrologueEpilogue.epi.ldp-x29-x30.376761.json │ │ │ ├── java.PrologueEpilogue.epi.ret.377192.json │ │ │ ├── java.PrologueEpilogue.stp-fp-lr.json │ │ │ ├── java.PrologueEpilogue.sub-sp-sp.json │ │ │ ├── java.VdsoPressure.osJavaTimeNanos.649996.json │ │ │ ├── node1600-inlining.json │ │ │ ├── node16110-inlining.json │ │ │ ├── node1640-inlining.json │ │ │ ├── node1660-inlining.json │ │ │ ├── node1890-inlining.json │ │ │ ├── node2010-inlining.json │ │ │ ├── node2110-inlining.json │ │ │ ├── perl-5.38-debian.json │ │ │ ├── php-8.2.10-prime.json │ │ │ ├── php-8.2.7-prime.json │ │ │ ├── php81.571415.json │ │ │ ├── python-3.10.12-nix-fib.json │ │ │ ├── python37.stringbench.10656.json │ │ │ ├── ruby-2.7.8p225-loop.json │ │ │ ├── ruby-3.0.4p208-loop.json │ │ │ ├── ruby-3.0.6p216-loop.json │ │ │ ├── ruby-3.1.0p0-loop.json │ │ │ ├── ruby-3.1.4p223-loop.json │ │ │ ├── ruby-3.2.2-loop.json │ │ │ ├── stackalign.19272.json │ │ │ ├── stackalign.67475.json │ │ │ ├── stackalign.7265.json │ │ │ └── vdso-frame.json │ ├── testsources │ │ ├── c │ │ │ ├── brokenstack.c │ │ │ ├── cpuhog.c │ │ │ ├── sig.c │ │ │ └── stackalign.c │ │ ├── dotnet │ │ │ └── helloworld │ │ │ │ ├── Program.cs │ │ │ │ └── helloworld.csproj │ │ ├── go │ │ │ └── hello.go │ │ ├── graalvm │ │ │ ├── .gitignore │ │ │ ├── HelloGraal.java │ │ │ ├── Makefile │ │ │ └── README.md │ │ ├── java │ │ │ ├── Deopt.java │ │ │ ├── DeoptFoo.java │ │ │ ├── HelloWorld.java │ │ │ ├── Lambda1.java │ │ │ ├── Prof1.java │ │ │ ├── Prof2.java │ │ │ ├── PrologueEpilogue.java │ │ │ ├── ShaShenanigans.java │ │ │ ├── VdsoPressure.java │ │ │ └── javagdbinit │ │ ├── node │ │ │ ├── async.js │ │ │ ├── hello.js │ │ │ ├── hello2.js │ │ │ ├── inlining.js │ │ │ └── test.js │ │ ├── perl │ │ │ ├── a.pl │ │ │ ├── gdb-dump-offsets.py │ │ │ └── hi.pl │ │ ├── php │ │ │ ├── gdb-dump-offsets.py │ │ │ ├── php_forever.php │ │ │ └── prime.php │ │ ├── python │ │ │ ├── expat.py │ │ │ ├── fib.py │ │ │ └── gdb-dump-offsets.py │ │ └── ruby │ │ │ ├── gdb-dump-offsets.py │ │ │ └── loop.rb │ └── upload.go ├── errors-codegen │ ├── bpf.h.template │ ├── errors.json │ └── main.go ├── fake-apm-agent │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── fake-apm-agent-lib.c │ └── fake-apm-agent.c ├── file_id.sh ├── stackdeltas │ ├── .gitignore │ └── stackdeltas.go └── zstpak │ ├── .gitignore │ ├── lib │ ├── zstpak.go │ └── zstpak_test.go │ └── main.go ├── tpbase ├── assembly_decode.go ├── assembly_decode_amd64.go ├── assembly_decode_arm64.go ├── assembly_decode_test.go ├── fsbase_decode_amd64.c ├── fsbase_decode_amd64.h ├── libc.go ├── libc_amd64.go ├── libc_arm64.go ├── libc_decode_amd64.c ├── libc_decode_amd64.h ├── libc_test.go └── tpbase.go ├── tracehandler ├── metrics.go ├── tracehandler.go └── tracehandler_test.go ├── tracer ├── ebpf_integration_test.go ├── events.go ├── helper.go ├── helper_test.go ├── maccess.go ├── probe_linux.go ├── probe_other.go ├── systemconfig.go ├── tpbase.go ├── tracepoints.go ├── tracer.go └── types │ ├── parse.go │ └── parse_test.go ├── traceutil ├── traceutil.go └── traceutil_test.go ├── util ├── util.go └── util_test.go ├── vc └── vc.go └── zydis ├── README.md ├── Zydis.c ├── Zydis.h └── zydis.go /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | CC_aarch64_unknown_linux_musl = "aarch64-linux-musl-gcc" 3 | CC_x86_64_unknown_linux_musl = "x86_64-linux-musl-gcc" 4 | 5 | # Zydis CMake config requires a C++ compiler for the test cases but the musl 6 | # toolchain doesn't have one. We simply force the compiler to `g++` here to 7 | # trick CMake into passing the check for a C++ compiler: it isn't actually 8 | # used anyway. 9 | TARGET_CXX = "g++" 10 | -------------------------------------------------------------------------------- /.codespellignore: -------------------------------------------------------------------------------- 1 | ba 2 | fo 3 | opne 4 | optimyze 5 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | # https://github.com/codespell-project/codespell 2 | [codespell] 3 | builtin = clear,rare,informal 4 | check-filenames = 5 | check-hidden = 6 | ignore-words = .codespellignore 7 | interactive = 1 8 | skip = .git,AUTHORS.md,go.mod,go.sum,LICENSES,zydis 9 | uri-ignore-words-list = * 10 | write = 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .cache 2 | go 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | ##################################################### 2 | # 3 | # List of approvers for this repository 4 | # 5 | ##################################################### 6 | # 7 | # Learn about membership in OpenTelemetry community: 8 | # https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md 9 | # 10 | # 11 | # Learn about CODEOWNERS file format: 12 | # https://help.github.com/en/articles/about-code-owners 13 | # 14 | 15 | * @open-telemetry/ebpf-profiler-maintainers @open-telemetry/ebpf-profiler-approvers 16 | 17 | CODEOWNERS @open-telemetry/ebpf-profiler-maintainers 18 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:best-practices", 5 | "helpers:pinGitHubActionDigestsToSemver" 6 | ], 7 | "packageRules": [ 8 | { 9 | "groupName": "Go dependencies", 10 | "matchManagers": ["gomod"], 11 | "schedule": ["before 8am every weekday"] 12 | }, 13 | { 14 | "groupName": "Dockerfile dependencies", 15 | "matchManagers": ["dockerfile"], 16 | "schedule": ["before 8am every weekday"] 17 | }, 18 | { 19 | "groupName": "GitHub Actions", 20 | "matchManagers": ["github-actions"], 21 | "schedule": ["before 8am every weekday"] 22 | }, 23 | { 24 | "groupName": "Other dependencies", 25 | "matchManagers": ["!gomod", "!dockerfile", "!github-actions"], 26 | "schedule": ["before 8am every weekday"] 27 | } 28 | ], 29 | "labels": [ 30 | "dependencies" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: "21 6 * * 1" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze Go (${{ matrix.target_arch }}) 14 | if: ${{ github.actor != 'dependabot[bot]' && github.repository == 'open-telemetry/opentelemetry-ebpf-profiler' }} 15 | runs-on: ubuntu-24.04 16 | strategy: 17 | matrix: 18 | target_arch: [amd64, arm64] 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | 23 | - name: Set up environment 24 | uses: ./.github/workflows/env 25 | 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3 28 | with: 29 | languages: go 30 | 31 | - name: Build Artifact 32 | run: | 33 | make TARGET_ARCH=${{ matrix.target_arch }} 34 | 35 | - name: Perform CodeQL Analysis 36 | uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3 37 | with: 38 | category: "/language:Go" 39 | timeout-minutes: 10 40 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | name: codespell 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | jobs: 8 | codespell: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Install codespell 12 | run: sudo apt-get install codespell 13 | - name: Checkout Repo 14 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | - name: Codespell 16 | run: make codespell 17 | -------------------------------------------------------------------------------- /.github/workflows/fossa.yml: -------------------------------------------------------------------------------- 1 | name: FOSSA scanning 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | fossa: 13 | runs-on: ubuntu-latest 14 | if: github.repository == 'open-telemetry/opentelemetry-ebpf-profiler' 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 17 | 18 | - uses: fossas/fossa-action@93a52ecf7c3ac7eb40f5de77fd69b1a19524de94 # v1.5.0 19 | with: 20 | api-key: ${{secrets.FOSSA_API_KEY}} 21 | team: OpenTelemetry 22 | -------------------------------------------------------------------------------- /.github/workflows/ossf-scorecard.yml: -------------------------------------------------------------------------------- 1 | name: OSSF Scorecard 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: "31 6 * * 4" # once a week 9 | workflow_dispatch: 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | analysis: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | # Needed for Code scanning upload 18 | security-events: write 19 | # Needed for GitHub OIDC token if publish_results is true 20 | id-token: write 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | persist-credentials: false 25 | 26 | - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 27 | with: 28 | results_file: results.sarif 29 | results_format: sarif 30 | publish_results: true 31 | 32 | # Upload the results as artifacts (optional). Commenting out will disable 33 | # uploads of run results in SARIF format to the repository Actions tab. 34 | # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts 35 | - name: "Upload artifact" 36 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 37 | with: 38 | name: SARIF file 39 | path: results.sarif 40 | retention-days: 5 41 | 42 | # Upload the results to GitHub's code scanning dashboard (optional). 43 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 44 | - name: "Upload to code-scanning" 45 | uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 46 | with: 47 | sarif_file: results.sarif 48 | -------------------------------------------------------------------------------- /.github/workflows/push-docker-image.yml: -------------------------------------------------------------------------------- 1 | name: "Update builder docker image" 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | paths: 7 | - "Dockerfile" 8 | 9 | jobs: 10 | build-and-push: 11 | runs-on: ubuntu-latest 12 | if: github.repository == 'open-telemetry/opentelemetry-ebpf-profiler' 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | - name: Login to Docker Hub 17 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 18 | with: 19 | username: ${{ secrets.DOCKER_USERNAME }} 20 | password: ${{ secrets.DOCKER_PASSWORD }} 21 | - name: Set up QEMU 22 | uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 23 | - name: Set up Docker Buildx 24 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 25 | - name: Set current timestamp tag 26 | id: tag 27 | run: | 28 | echo "tag=$(date +%Y%m%d%H%M)" >> $GITHUB_OUTPUT 29 | - name: Build and push 30 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 31 | with: 32 | push: true 33 | file: Dockerfile 34 | platforms: linux/amd64,linux/arm64 35 | tags: otel/opentelemetry-ebpf-profiler-dev:latest,otel/opentelemetry-ebpf-profiler-dev:${{ steps.tag.outputs.tag }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.pb.go 3 | .cache 4 | /.idea 5 | /go 6 | ebpf-profiler 7 | ci-kernels 8 | # Ignore target directory 9 | target/* 10 | # But not these specific paths 11 | !target/x86_64-unknown-linux-musl/release/libsymblib_capi.a 12 | !target/aarch64-unknown-linux-musl/release/libsymblib_capi.a 13 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | ## Open-Source contributors 2 | 3 | For contributors statistics that occurred after the profiling agent was open sourced, please refer to [the GitHub statistics](https://github.com/open-telemetry/opentelemetry-ebpf-profiler/graphs/contributors). 4 | 5 | ## Pre-OSS Optimyze/Elastic contributors 6 | 7 | - [@amannocci](https://github.com/amannocci) 8 | - [@athre0z](https://github.com/athre0z) 9 | - [@cauemarcondes](https://github.com/cauemarcondes) 10 | - [@christos68k](https://github.com/christos68k) 11 | - [@danielmitterdorfer](https://github.com/danielmitterdorfer) 12 | - [@dmathieu](https://github.com/dmathieu) 13 | - [@fabled](https://github.com/fabled) 14 | - [@florianl](https://github.com/florianl) 15 | - [@inge4pres](https://github.com/inge4pres) 16 | - [@iogbole](https://github.com/iogbole) 17 | - [@jbcrail](https://github.com/jbcrail) 18 | - [@joerowell](https://github.com/joerowell) 19 | - [@kruskall](https://github.com/kruskall) 20 | - [@mejofi](https://github.com/mejofi) 21 | - [@reakaleek](https://github.com/reakaleek) 22 | - [@rockdaboot](https://github.com/rockdaboot) 23 | - [@sboomsma](https://github.com/sboomsma) 24 | - [@SeanHeelan](https://github.com/SeanHeelan) 25 | - [@thomasdullien](https://github.com/thomasdullien) 26 | - [@v1v](https://github.com/v1v) 27 | - [@vikmik](https://github.com/vikmik) 28 | -------------------------------------------------------------------------------- /LICENSES/github.com/cespare/xxhash/v2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Caleb Spare 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /LICENSES/github.com/cilium/ebpf/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nathan Sweet 4 | Copyright (c) 2018, 2019 Cloudflare 5 | Copyright (c) 2019 Authors of Cilium 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSES/github.com/elastic/go-freelru/NOTICE: -------------------------------------------------------------------------------- 1 | Go LRU Hashmap 2 | Copyright 2022 Elasticsearch B.V. 3 | -------------------------------------------------------------------------------- /LICENSES/github.com/elastic/go-perf/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/github.com/google/uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009,2014 Google Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/github.com/josharian/native/license: -------------------------------------------------------------------------------- 1 | Copyright 2020 Josh Bleecher Snyder 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /LICENSES/github.com/jsimonetti/rtnetlink/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | =========== 3 | 4 | Copyright (C) 2016 Jeroen Simonetti 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /LICENSES/github.com/json-iterator/go/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 json-iterator 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSES/github.com/klauspost/cpuid/v2/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Klaus Post 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LICENSES/github.com/mdlayher/netlink/LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (C) 2016-2022 Matt Layher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /LICENSES/github.com/mdlayher/socket/LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (C) 2021 Matt Layher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /LICENSES/github.com/sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSES/github.com/zeebo/xxh3/LICENSE: -------------------------------------------------------------------------------- 1 | xxHash Library 2 | Copyright (c) 2012-2014, Yann Collet 3 | Copyright (c) 2019, Jeff Wendling 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, this 13 | list of conditions and the following disclaimer in the documentation and/or 14 | other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LICENSES/go.uber.org/multierr/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2021 Uber Technologies, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/arch/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/exp/constraints/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/net/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/sync/errgroup/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/sys/unix/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/golang.org/x/text/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/google.golang.org/grpc/NOTICE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 gRPC authors. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /LICENSES/google.golang.org/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSES/zyantific/zydis/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2024 Florian Bernd 4 | Copyright (c) 2014-2024 Joel Höner 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /asm/amd/insn.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package amd // import "go.opentelemetry.io/ebpf-profiler/asm/amd" 5 | import "bytes" 6 | 7 | // https://www.felixcloutier.com/x86/endbr64 8 | var opcodeEndBr64 = []byte{0xf3, 0x0f, 0x1e, 0xfa} 9 | 10 | // DecodeSkippable decodes an instruction that we don't care much about and are going to skip, 11 | // as golang.org/x/arch/x86/x86asm fails to decode it. 12 | // The second returned argument is the size of the decoded instruction to skip. 13 | func DecodeSkippable(code []byte) (ok bool, size int) { 14 | switch { 15 | case bytes.HasPrefix(code, opcodeEndBr64): 16 | return true, len(opcodeEndBr64) 17 | default: 18 | return false, 0 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /asm/amd/insn_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package amd 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestEndBr64(t *testing.T) { 13 | res, n := DecodeSkippable([]byte{0xF3, 0x0F, 0x1E, 0xFA}) 14 | assert.True(t, res) 15 | assert.Equal(t, 4, n) 16 | 17 | res, _ = DecodeSkippable([]byte{}) 18 | assert.False(t, res) 19 | } 20 | -------------------------------------------------------------------------------- /asm/amd/regs_state.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package amd // import "go.opentelemetry.io/ebpf-profiler/asm/amd" 5 | 6 | import "golang.org/x/arch/x86/x86asm" 7 | 8 | // regIndex returns index into RegsState.regs 9 | func regIndex(reg x86asm.Reg) int { 10 | switch reg { 11 | case x86asm.RAX, x86asm.EAX: 12 | return 1 13 | case x86asm.RBX, x86asm.EBX: 14 | return 2 15 | case x86asm.RCX, x86asm.ECX: 16 | return 3 17 | case x86asm.RDX, x86asm.EDX: 18 | return 4 19 | case x86asm.RDI, x86asm.EDI: 20 | return 5 21 | case x86asm.RSI, x86asm.ESI: 22 | return 6 23 | case x86asm.RBP, x86asm.EBP: 24 | return 7 25 | case x86asm.R8, x86asm.R8L: 26 | return 8 27 | case x86asm.R9, x86asm.R9L: 28 | return 9 29 | case x86asm.R10, x86asm.R10L: 30 | return 10 31 | case x86asm.R11, x86asm.R11L: 32 | return 11 33 | case x86asm.R12, x86asm.R12L: 34 | return 12 35 | case x86asm.R13, x86asm.R13L: 36 | return 13 37 | case x86asm.R14, x86asm.R14L: 38 | return 14 39 | case x86asm.R15, x86asm.R15L: 40 | return 15 41 | case x86asm.RSP, x86asm.ESP: 42 | return 16 43 | case x86asm.RIP: 44 | return 17 45 | default: 46 | return 0 47 | } 48 | } 49 | 50 | type RegsState struct { 51 | regs [18]regState 52 | } 53 | 54 | func (r *RegsState) Set(reg x86asm.Reg, value, loadedFrom uint64) { 55 | r.regs[regIndex(reg)].Value = value 56 | r.regs[regIndex(reg)].LoadedFrom = loadedFrom 57 | } 58 | 59 | func (r *RegsState) Get(reg x86asm.Reg) (value, loadedFrom uint64) { 60 | return r.regs[regIndex(reg)].Value, r.regs[regIndex(reg)].LoadedFrom 61 | } 62 | 63 | type regState struct { 64 | LoadedFrom uint64 65 | Value uint64 66 | } 67 | -------------------------------------------------------------------------------- /collector/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package collector // import "go.opentelemetry.io/ebpf-profiler/collector" 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | "time" 10 | 11 | "go.opentelemetry.io/collector/component" 12 | "go.opentelemetry.io/collector/consumer/xconsumer" 13 | "go.opentelemetry.io/collector/receiver" 14 | "go.opentelemetry.io/collector/receiver/xreceiver" 15 | 16 | "go.opentelemetry.io/ebpf-profiler/collector/internal" 17 | "go.opentelemetry.io/ebpf-profiler/internal/controller" 18 | ) 19 | 20 | var ( 21 | typeStr = component.MustNewType("profiling") 22 | 23 | errInvalidConfig = errors.New("invalid config") 24 | ) 25 | 26 | // NewFactory creates a factory for the receiver. 27 | func NewFactory() receiver.Factory { 28 | return xreceiver.NewFactory( 29 | typeStr, 30 | defaultConfig, 31 | xreceiver.WithProfiles(createProfilesReceiver, component.StabilityLevelAlpha)) 32 | } 33 | 34 | func createProfilesReceiver( 35 | _ context.Context, 36 | _ receiver.Settings, //nolint:gocritic // we must respect the collector API 37 | baseCfg component.Config, 38 | nextConsumer xconsumer.Profiles) (xreceiver.Profiles, error) { 39 | cfg, ok := baseCfg.(*controller.Config) 40 | if !ok { 41 | return nil, errInvalidConfig 42 | } 43 | 44 | return internal.NewController(cfg, nextConsumer) 45 | } 46 | 47 | func defaultConfig() component.Config { 48 | return &controller.Config{ 49 | ReporterInterval: 5 * time.Second, 50 | MonitorInterval: 5 * time.Second, 51 | SamplesPerSecond: 20, 52 | ProbabilisticInterval: 1 * time.Minute, 53 | ProbabilisticThreshold: 100, 54 | Tracers: "all", 55 | ClockSyncInterval: 3 * time.Minute, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /collector/factory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package collector 5 | 6 | import ( 7 | "context" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/require" 11 | "go.opentelemetry.io/collector/component" 12 | "go.opentelemetry.io/collector/consumer/consumertest" 13 | "go.opentelemetry.io/collector/receiver/receivertest" 14 | ) 15 | 16 | func TestNewFactory(t *testing.T) { 17 | f := NewFactory() 18 | require.NotNil(t, f) 19 | } 20 | 21 | func TestCreateProfilesReceiver(t *testing.T) { 22 | for _, tt := range []struct { 23 | name string 24 | config component.Config 25 | 26 | wantError error 27 | }{ 28 | { 29 | name: "Default config", 30 | config: defaultConfig(), 31 | }, 32 | { 33 | name: "Nil config", 34 | wantError: errInvalidConfig, 35 | }, 36 | } { 37 | t.Run(tt.name, func(t *testing.T) { 38 | t.Parallel() 39 | 40 | _, err := createProfilesReceiver( 41 | context.Background(), 42 | receivertest.NewNopSettings(), 43 | tt.config, 44 | consumertest.NewNop(), 45 | ) 46 | require.ErrorIs(t, err, tt.wantError) 47 | }) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /design-docs/00000-example-docs/04359-remove-bpf-hashing/known-trace-metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/design-docs/00000-example-docs/04359-remove-bpf-hashing/known-trace-metrics.png -------------------------------------------------------------------------------- /design-docs/00000-example-docs/04359-remove-bpf-hashing/memcpy-cost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/design-docs/00000-example-docs/04359-remove-bpf-hashing/memcpy-cost.png -------------------------------------------------------------------------------- /design-docs/00000-example-docs/04359-remove-bpf-hashing/option2-ghidra-workload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/design-docs/00000-example-docs/04359-remove-bpf-hashing/option2-ghidra-workload.png -------------------------------------------------------------------------------- /design-docs/00000-example-docs/04359-remove-bpf-hashing/option2-idle-workload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/design-docs/00000-example-docs/04359-remove-bpf-hashing/option2-idle-workload.png -------------------------------------------------------------------------------- /design-docs/00000-example-docs/README.md: -------------------------------------------------------------------------------- 1 | This directory contains two old design documents from times before the agent 2 | was donated to OTel and open-sourced in the process. The documents are provided 3 | primarily as examples of how a design document can be structured. 4 | -------------------------------------------------------------------------------- /internal/helpers/kernel.go: -------------------------------------------------------------------------------- 1 | package helpers // import "go.opentelemetry.io/ebpf-profiler/internal/helpers" 2 | 3 | import ( 4 | "fmt" 5 | 6 | "go.opentelemetry.io/ebpf-profiler/tracer" 7 | ) 8 | 9 | // GetKernelVersion returns the current version of the kernel 10 | func GetKernelVersion() (string, error) { 11 | major, minor, patch, err := tracer.GetCurrentKernelVersion() 12 | if err != nil { 13 | return "", err 14 | } 15 | return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil 16 | } 17 | -------------------------------------------------------------------------------- /interpreter/dotnet/nativereader_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package dotnet 5 | 6 | import ( 7 | "bytes" 8 | "encoding/hex" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | func TestNativeReader(t *testing.T) { 16 | testCases := []struct { 17 | data string 18 | expected uint32 19 | }{ 20 | {"18", 12}, 21 | {"a10f", 1000}, 22 | } 23 | 24 | for _, test := range testCases { 25 | t.Run(test.data, func(t *testing.T) { 26 | data, err := hex.DecodeString(test.data) 27 | require.NoError(t, err, "Hex decoding failed") 28 | 29 | decoder := nativeReader{ 30 | ReaderAt: bytes.NewReader(data), 31 | } 32 | value, _, err := decoder.Uint(0) 33 | require.NoError(t, err, "Error") 34 | assert.Equal(t, test.expected, value, "Wrong native decoding") 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /interpreter/dotnet/nibblereader_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package dotnet 5 | 6 | import ( 7 | "bytes" 8 | "encoding/hex" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | func TestNibbleReader(t *testing.T) { 16 | testCases := []struct { 17 | data string 18 | expected uint32 19 | }{ 20 | // https://github.com/dotnet/runtime/blob/v7.0.15/src/coreclr/inc/nibblestream.h#L32-L46 21 | {"00", 0}, 22 | {"71", 1}, 23 | {"07", 7}, 24 | {"09", 8}, 25 | {"19", 9}, 26 | {"7f", 63}, 27 | {"8900", 64}, // incorrect example in dotnet code 28 | {"8901", 65}, // incorrect example in dotnet code 29 | {"ff07", 511}, 30 | {"8908", 512}, 31 | {"8918", 513}, 32 | } 33 | 34 | for _, test := range testCases { 35 | t.Run(test.data, func(t *testing.T) { 36 | data, err := hex.DecodeString(test.data) 37 | require.NoError(t, err, "Hex decoding failed") 38 | 39 | decoder := nibbleReader{ 40 | ByteReader: bytes.NewReader(data), 41 | } 42 | value := decoder.Uint32() 43 | require.NoError(t, decoder.Error(), "Error") 44 | assert.Equal(t, test.expected, value, "Wrong nibble decoding") 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /interpreter/go/go_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package golang // import "go.opentelemetry.io/ebpf-profiler/interpreter/go" 7 | 8 | /* 9 | #cgo LDFLAGS: ${SRCDIR}/../../target/x86_64-unknown-linux-musl/release/libsymblib_capi.a 10 | */ 11 | import "C" 12 | -------------------------------------------------------------------------------- /interpreter/go/go_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package golang // import "go.opentelemetry.io/ebpf-profiler/interpreter/go" 7 | 8 | /* 9 | #cgo LDFLAGS: ${SRCDIR}/../../target/aarch64-unknown-linux-musl/release/libsymblib_capi.a 10 | */ 11 | import "C" 12 | -------------------------------------------------------------------------------- /interpreter/hotspot/demangle_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package hotspot 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestJavaDemangling(t *testing.T) { 13 | cases := []struct { 14 | klass, method, signature, demangled string 15 | }{ 16 | {"java/lang/Object", "", "()V", 17 | "void java.lang.Object.()"}, 18 | {"java/lang/StringLatin1", "equals", "([B[B)Z", 19 | "boolean java.lang.StringLatin1.equals(byte[], byte[])"}, 20 | {"java/util/zip/ZipUtils", "CENSIZ", "([BI)J", 21 | "long java.util.zip.ZipUtils.CENSIZ(byte[], int)"}, 22 | {"java/util/regex/Pattern$BmpCharProperty", "match", 23 | "(Ljava/util/regex/Matcher;ILjava/lang/CharSequence;)Z", 24 | "boolean java.util.regex.Pattern$BmpCharProperty.match" + 25 | "(java.util.regex.Matcher, int, java.lang.CharSequence)"}, 26 | {"java/lang/AbstractStringBuilder", "appendChars", "(Ljava/lang/String;II)V", 27 | "void java.lang.AbstractStringBuilder.appendChars" + 28 | "(java.lang.String, int, int)"}, 29 | {"foo/test", "bar", "([)J", "long foo.test.bar()"}, 30 | } 31 | 32 | for _, c := range cases { 33 | demangled := demangleJavaMethod(c.klass, c.method, c.signature) 34 | assert.Equal(t, c.demangled, demangled) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /interpreter/hotspot/instance_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package hotspot 5 | 6 | import ( 7 | "bytes" 8 | "encoding/binary" 9 | "strings" 10 | "testing" 11 | 12 | "github.com/elastic/go-freelru" 13 | "github.com/stretchr/testify/assert" 14 | "github.com/stretchr/testify/require" 15 | "go.opentelemetry.io/ebpf-profiler/libpf" 16 | "go.opentelemetry.io/ebpf-profiler/lpm" 17 | "go.opentelemetry.io/ebpf-profiler/remotememory" 18 | ) 19 | 20 | func TestJavaSymbolExtraction(t *testing.T) { 21 | id := hotspotData{} 22 | vmd, _ := id.GetOrInit(func() (hotspotVMData, error) { 23 | vmd := hotspotVMData{} 24 | vmd.vmStructs.Symbol.Length = 2 25 | vmd.vmStructs.Symbol.Body = 4 26 | return vmd, nil 27 | }) 28 | 29 | maxLength := 1024 30 | sym := make([]byte, vmd.vmStructs.Symbol.Body+uint(maxLength)) 31 | rd := bytes.NewReader(sym) 32 | rm := remotememory.RemoteMemory{ReaderAt: rd} 33 | 34 | addrToSymbol, err := freelru.New[libpf.Address, string](2, libpf.Address.Hash32) 35 | require.NoError(t, err, "symbol cache failed") 36 | 37 | ii := hotspotInstance{ 38 | d: &id, 39 | rm: rm, 40 | addrToSymbol: addrToSymbol, 41 | prefixes: libpf.Set[lpm.Prefix]{}, 42 | stubs: map[libpf.Address]StubRoutine{}, 43 | } 44 | 45 | str := strings.Repeat("a", maxLength) 46 | copy(sym[vmd.vmStructs.Symbol.Body:], str) 47 | for i := 0; i <= maxLength; i++ { 48 | binary.LittleEndian.PutUint16(sym[vmd.vmStructs.Symbol.Length:], uint16(i)) 49 | got := ii.getSymbol(0) 50 | assert.Equal(t, str[:i], got, "symbol length %d mismatched read", i) 51 | ii.addrToSymbol.Purge() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /interpreter/hotspot/recordingreader_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package hotspot 5 | 6 | import ( 7 | "bytes" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestRecordingReader(t *testing.T) { 15 | data := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} 16 | 17 | rr := newRecordingReader(bytes.NewReader(data), 0, 2) 18 | for i := 0; i < len(data)-1; i++ { 19 | b, err := rr.ReadByte() 20 | require.NoError(t, err) 21 | assert.Equal(t, data[i], b) 22 | } 23 | assert.Len(t, rr.GetBuffer(), len(data)-1) 24 | } 25 | -------------------------------------------------------------------------------- /interpreter/hotspot/unsigned5_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package hotspot 5 | 6 | import ( 7 | "bytes" 8 | "io" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | // TestJavaLineNumbers tests that the Hotspot delta encoded line table decoding works. 16 | // The set here is an actually table extracting from JVM. It is fairly easy to encode 17 | // these numbers if needed, but we don't need to generate them currently for anything. 18 | func TestJavaLineNumbers(t *testing.T) { 19 | bciLine := []struct { 20 | bci, line uint32 21 | }{ 22 | {0, 478}, 23 | {5, 479}, 24 | {9, 480}, 25 | {19, 481}, 26 | {26, 482}, 27 | {33, 483}, 28 | {47, 490}, 29 | {50, 485}, 30 | {52, 486}, 31 | {58, 490}, 32 | {61, 488}, 33 | {63, 489}, 34 | {68, 491}, 35 | } 36 | 37 | decoder := unsigned5Decoder{ 38 | r: bytes.NewReader([]byte{ 39 | 255, 0, 252, 11, 41, 33, 81, 57, 57, 119, 40 | 255, 6, 9, 17, 52, 255, 6, 3, 17, 42, 0}), 41 | } 42 | 43 | var bci, line uint32 44 | for i := 0; i < len(bciLine); i++ { 45 | err := decoder.decodeLineTableEntry(&bci, &line) 46 | require.NoError(t, err) 47 | assert.Equal(t, bciLine[i].bci, bci) 48 | assert.Equal(t, bciLine[i].line, line) 49 | } 50 | err := decoder.decodeLineTableEntry(&bci, &line) 51 | assert.ErrorIs(t, err, io.EOF, "line table not empty at end") 52 | } 53 | -------------------------------------------------------------------------------- /interpreter/instancestubs.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package interpreter // import "go.opentelemetry.io/ebpf-profiler/interpreter" 5 | 6 | import ( 7 | "go.opentelemetry.io/ebpf-profiler/host" 8 | "go.opentelemetry.io/ebpf-profiler/libpf" 9 | "go.opentelemetry.io/ebpf-profiler/metrics" 10 | "go.opentelemetry.io/ebpf-profiler/process" 11 | "go.opentelemetry.io/ebpf-profiler/reporter" 12 | "go.opentelemetry.io/ebpf-profiler/tpbase" 13 | ) 14 | 15 | // InstanceStubs provides empty implementations of Instance hooks that are 16 | // not mandatory for a Instance implementation. 17 | type InstanceStubs struct { 18 | } 19 | 20 | func (is *InstanceStubs) SynchronizeMappings(EbpfHandler, reporter.SymbolReporter, process.Process, 21 | []process.Mapping) error { 22 | return nil 23 | } 24 | 25 | func (is *InstanceStubs) UpdateTSDInfo(EbpfHandler, libpf.PID, tpbase.TSDInfo) error { 26 | return nil 27 | } 28 | 29 | func (is *InstanceStubs) Symbolize(reporter.SymbolReporter, *host.Frame, *libpf.Trace) error { 30 | return ErrMismatchInterpreterType 31 | } 32 | 33 | func (is *InstanceStubs) GetAndResetMetrics() ([]metrics.Metric, error) { 34 | return []metrics.Metric{}, nil 35 | } 36 | -------------------------------------------------------------------------------- /interpreter/php/decode_amd64.h: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build amd64 5 | #ifndef __INCLUDED_PHP_DECODE_X86_64__ 6 | #define __INCLUDED_PHP_DECODE_X86_64__ 7 | #include 8 | #include 9 | 10 | // Note: to make it easier to convert C error codes into Go error strings 11 | // we place an enum here that represents the set of allowed 12 | // error codes. These represent the errors that could 13 | // occur during the execution of each function. 14 | enum x86PHPJITDecodingCodes { 15 | // No error: happens when no error happens. 16 | NO_ERROR = 0, 17 | // Happens when we iterate over the whole blob 18 | // without finding the target instruction 19 | NOT_FOUND_ERROR = 1, 20 | // Happens when we encounter a CALL/JMP before finding 21 | // the target instruction 22 | EARLY_RETURN_ERROR = 2, 23 | // Happens when we fail to decode due to a small blob. 24 | DECODING_ERROR = 3, 25 | }; 26 | 27 | int retrieveExecuteExJumpLabelAddress(const uint8_t * const code, const size_t codesize, 28 | const uint64_t rip_base, uint64_t * const out); 29 | int retrieveZendVMKind(const uint8_t * const code, const size_t codesize, uint64_t * const out); 30 | int retrieveJITBufferPtr(const uint8_t * const code, const size_t codesize, 31 | const uint64_t rip_base, uint64_t * const buffer_ptr, 32 | uint64_t * const size_ptr); 33 | #endif 34 | -------------------------------------------------------------------------------- /legal/add-non-go.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to append legal information for non Go dependencies. 4 | 5 | set -eu 6 | set -o pipefail 7 | 8 | # Set the input file to the first argument or default to foobar.json 9 | input_file="${1:-non-go-dependencies.json}" 10 | 11 | # Set the prefix directory to the second argument or default to current directory 12 | prefix_dir="${2:-.}" 13 | 14 | # Ensure prefix_dir ends with a slash 15 | prefix_dir="${prefix_dir%/}/" 16 | 17 | 18 | # Check if the file exists 19 | if [ ! -f "$input_file" ]; then 20 | echo "Error: Input file '$input_file' not found." 21 | exit 1 22 | fi 23 | 24 | # Function to process each dependency 25 | process_dependency() { 26 | local dep="$1" 27 | 28 | # Extract values from JSON using jq 29 | dependency=$(echo "$dep" | jq -r '.Dependency') 30 | licence_file=$(echo "$dep" | jq -r '.LicenceFile') 31 | 32 | # Create directory structure 33 | dir_structure="./${prefix_dir}${dependency}" 34 | mkdir -p "$dir_structure" 35 | 36 | # Extract the filename from the LicenceFile URL 37 | filename=$(basename "$licence_file") 38 | 39 | # Download the license file 40 | wget -q -O "$dir_structure/$filename" "$licence_file" 41 | 42 | if [ $? -eq 0 ]; then 43 | echo "License file for $dependency downloaded successfully to $dir_structure/$filename" 44 | else 45 | echo "Failed to download license file for $dependency" 46 | fi 47 | } 48 | 49 | # Read and process the JSON file 50 | jq -c '.[]' "$input_file" | while read -r dep; do 51 | process_dependency "$dep" 52 | done -------------------------------------------------------------------------------- /legal/non-go-dependencies.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Dependency": "zyantific/zydis", 4 | "Version": "v4.1.0", 5 | "Licence": "MIT", 6 | "URL": "https://zydis.re", 7 | "LicenceFile": "https://raw.githubusercontent.com/zyantific/zydis/v4.1.0/LICENSE" 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /libpf/address.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" 5 | 6 | import "go.opentelemetry.io/ebpf-profiler/libpf/hash" 7 | 8 | // Address represents an address, or offset within a process 9 | type Address uintptr 10 | 11 | // Hash32 returns a 32 bits hash of the input. 12 | // It's main purpose is to be used as key for caching. 13 | func (adr Address) Hash32() uint32 { 14 | return uint32(adr.Hash()) 15 | } 16 | 17 | // Hash returns a 64 bits hash of the input. 18 | func (adr Address) Hash() uint64 { 19 | return hash.Uint64(uint64(adr)) 20 | } 21 | -------------------------------------------------------------------------------- /libpf/apm.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" 5 | 6 | type APMSpanID [8]byte 7 | type APMTraceID [16]byte 8 | type APMTransactionID = APMSpanID 9 | 10 | var InvalidAPMSpanID = APMSpanID{0, 0, 0, 0, 0, 0, 0, 0} 11 | -------------------------------------------------------------------------------- /libpf/convenience.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" 5 | 6 | import ( 7 | "math/rand/v2" 8 | "reflect" 9 | "time" 10 | "unsafe" 11 | 12 | log "github.com/sirupsen/logrus" 13 | ) 14 | 15 | // AddJitter adds +/- jitter (jitter is [0..1]) to baseDuration 16 | func AddJitter(baseDuration time.Duration, jitter float64) time.Duration { 17 | if jitter < 0.0 || jitter > 1.0 { 18 | log.Errorf("Jitter (%f) out of range [0..1].", jitter) 19 | return baseDuration 20 | } 21 | //nolint:gosec 22 | return time.Duration((1 + jitter - 2*jitter*rand.Float64()) * float64(baseDuration)) 23 | } 24 | 25 | // SliceFrom converts a Go struct pointer or slice to []byte to read data into 26 | func SliceFrom(data any) []byte { 27 | var s []byte 28 | val := reflect.ValueOf(data) 29 | switch val.Kind() { 30 | case reflect.Slice: 31 | if val.Len() != 0 { 32 | e := val.Index(0) 33 | addr := e.Addr().UnsafePointer() 34 | l := val.Len() * int(e.Type().Size()) 35 | s = unsafe.Slice((*byte)(addr), l) 36 | } 37 | case reflect.Ptr: 38 | e := val.Elem() 39 | addr := e.Addr().UnsafePointer() 40 | l := int(e.Type().Size()) 41 | s = unsafe.Slice((*byte)(addr), l) 42 | default: 43 | panic("invalid type") 44 | } 45 | return s 46 | } 47 | -------------------------------------------------------------------------------- /libpf/frameid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | const ( 13 | fileIDLo = 0x77efa716a912a492 14 | fileIDHi = 0x17445787329fd29a 15 | addressOrLine = 0xe51c 16 | ) 17 | 18 | func TestFrameID(t *testing.T) { 19 | var fileID = NewFileID(fileIDLo, fileIDHi) 20 | 21 | tests := []struct { 22 | name string 23 | input string 24 | expected FrameID 25 | bytes []byte 26 | err error 27 | }{ 28 | { 29 | name: "frame base64", 30 | input: "d--nFqkSpJIXRFeHMp_SmgAAAAAAAOUc", 31 | expected: NewFrameID(fileID, addressOrLine), 32 | bytes: []byte{ 33 | 0x77, 0xef, 0xa7, 0x16, 0xa9, 0x12, 0xa4, 0x92, 0x17, 0x44, 0x57, 0x87, 34 | 0x32, 0x9f, 0xd2, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x1c, 35 | }, 36 | err: nil, 37 | }, 38 | } 39 | 40 | for _, test := range tests { 41 | test := test 42 | t.Run(test.name, func(t *testing.T) { 43 | frameID, err := NewFrameIDFromString(test.input) 44 | assert.Equal(t, test.err, err) 45 | assert.Equal(t, test.expected, frameID) 46 | 47 | // check if the roundtrip back to the input works 48 | assert.Equal(t, test.input, frameID.String()) 49 | 50 | assert.Equal(t, test.bytes, frameID.Bytes()) 51 | 52 | frameID, err = NewFrameIDFromBytes(frameID.Bytes()) 53 | assert.Equal(t, test.err, err) 54 | assert.Equal(t, test.expected, frameID) 55 | 56 | ip := []byte(frameID.AsIP()) 57 | bytes := frameID.Bytes() 58 | assert.Equal(t, bytes[:8], ip[:8]) 59 | assert.Equal(t, bytes[16:], ip[8:]) 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /libpf/frametype_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestFrameTypeFromString(t *testing.T) { 13 | // Simple check whether all FrameType values can be converted to string and back. 14 | for _, ft := range []FrameType{ 15 | unknownFrame, PHPFrame, PythonFrame, NativeFrame, KernelFrame, HotSpotFrame, RubyFrame, 16 | PerlFrame, V8Frame, DotnetFrame, AbortFrame} { 17 | t.Run(ft.String(), func(t *testing.T) { 18 | name := ft.String() 19 | result := FrameTypeFromString(name) 20 | require.Equal(t, ft, result) 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libpf/generics.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" 5 | 6 | // Set is a convenience alias for a map with a `Void` key. 7 | type Set[T comparable] map[T]Void 8 | 9 | // ToSlice converts the Set keys into a slice. 10 | func (s Set[T]) ToSlice() []T { 11 | slice := make([]T, 0, len(s)) 12 | for item := range s { 13 | slice = append(slice, item) 14 | } 15 | return slice 16 | } 17 | 18 | // MapKeysToSlice creates a slice from a map's keys. 19 | func MapKeysToSlice[K comparable, V any](m map[K]V) []K { 20 | slice := make([]K, 0, len(m)) 21 | for key := range m { 22 | slice = append(slice, key) 23 | } 24 | return slice 25 | } 26 | 27 | // SliceAllEqual checks whether all items in a slice have a given value. 28 | func SliceAllEqual[T comparable](s []T, value T) bool { 29 | for _, item := range s { 30 | if item != value { 31 | return false 32 | } 33 | } 34 | 35 | return true 36 | } 37 | -------------------------------------------------------------------------------- /libpf/hash/hash.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package hash provides the same hash primitives as used by the eBPF. 5 | // This file should be kept in sync with the eBPF tracemgmt.h. 6 | package hash // import "go.opentelemetry.io/ebpf-profiler/libpf/hash" 7 | 8 | // Uint32 computes a hash of a 32-bit uint using the finalizer function for Murmur. 9 | // 32-bit via https://en.wikipedia.org/wiki/MurmurHash#Algorithm 10 | func Uint32(x uint32) uint32 { 11 | x ^= x >> 16 12 | x *= 0x85ebca6b 13 | x ^= x >> 13 14 | x *= 0xc2b2ae35 15 | x ^= x >> 16 16 | return x 17 | } 18 | 19 | // Uint64 computes a hash of a 64-bit uint using the finalizer function for Murmur3 20 | // Via https://lemire.me/blog/2018/08/15/fast-strongly-universal-64-bit-hashing-everywhere/ 21 | func Uint64(x uint64) uint64 { 22 | x ^= x >> 33 23 | x *= 0xff51afd7ed558ccd 24 | x ^= x >> 33 25 | x *= 0xc4ceb9fe1a85ec53 26 | x ^= x >> 33 27 | return x 28 | } 29 | -------------------------------------------------------------------------------- /libpf/hash/hash_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package hash 5 | 6 | import ( 7 | "math" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestUint64(t *testing.T) { 14 | tests := map[string]struct { 15 | input uint64 16 | expect uint64 17 | }{ 18 | "0": {input: 0, expect: 0}, 19 | "1": {input: 1, expect: 12994781566227106604}, 20 | "uint16 max": {input: uint64(math.MaxUint16), expect: 6444452806975366496}, 21 | "uint32 max": {input: uint64(math.MaxUint32), expect: 14731816277868330182}, 22 | "uint64 max": {input: math.MaxUint64, expect: 7256831767414464289}, 23 | } 24 | 25 | for name, testcase := range tests { 26 | name := name 27 | testcase := testcase 28 | t.Run(name, func(t *testing.T) { 29 | result := Uint64(testcase.input) 30 | assert.Equal(t, testcase.expect, result) 31 | }) 32 | } 33 | } 34 | 35 | func TestUint32(t *testing.T) { 36 | tests := map[string]struct { 37 | input uint32 38 | expect uint32 39 | }{ 40 | "0": {input: 0, expect: 0}, 41 | "1": {input: 1, expect: 1364076727}, 42 | "uint16 max": {input: uint32(math.MaxUint16), expect: 2721820263}, 43 | "uint32 max": {input: math.MaxUint32, expect: 2180083513}, 44 | } 45 | 46 | for name, testcase := range tests { 47 | name := name 48 | testcase := testcase 49 | t.Run(name, func(t *testing.T) { 50 | result := Uint32(testcase.input) 51 | assert.Equal(t, testcase.expect, result) 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /libpf/libpf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package libpf 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestTraceType(t *testing.T) { 13 | tests := []struct { 14 | ty FrameType 15 | isErr bool 16 | interp InterpreterType 17 | str string 18 | }{ 19 | { 20 | ty: AbortFrame, 21 | isErr: true, 22 | interp: UnknownInterp, 23 | str: "abort-marker", 24 | }, 25 | { 26 | ty: PythonFrame, 27 | isErr: false, 28 | interp: Python, 29 | str: "cpython", 30 | }, 31 | { 32 | ty: NativeFrame.Error(), 33 | isErr: true, 34 | interp: Native, 35 | str: "native", 36 | }, 37 | } 38 | 39 | for _, test := range tests { 40 | assert.Equal(t, test.isErr, test.ty.IsError()) 41 | assert.Equal(t, test.interp, test.ty.Interpreter()) 42 | assert.Equal(t, test.str, test.ty.String()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /libpf/pfelf/addressmapper_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package pfelf 5 | 6 | import ( 7 | "os" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | "go.opentelemetry.io/ebpf-profiler/testsupport" 13 | ) 14 | 15 | func assertFileToVA(t *testing.T, mapper AddressMapper, fileAddress, virtualAddress uint64) { 16 | mappedAddress, ok := mapper.FileOffsetToVirtualAddress(fileAddress) 17 | assert.True(t, ok) 18 | assert.Equal(t, virtualAddress, mappedAddress) 19 | } 20 | 21 | func TestAddressMapper(t *testing.T) { 22 | debugExePath, err := testsupport.WriteTestExecutable2() 23 | require.NoError(t, err) 24 | defer os.Remove(debugExePath) 25 | 26 | ef, err := Open(debugExePath) 27 | require.NoError(t, err) 28 | 29 | mapper := ef.GetAddressMapper() 30 | assertFileToVA(t, mapper, 0x1000, 0x401000) 31 | assertFileToVA(t, mapper, 0x1010, 0x401010) 32 | } 33 | -------------------------------------------------------------------------------- /libpf/pfelf/elfopener.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // package pfelf implements functions for processing of ELF files and extracting data from 5 | // them. This file implements an interface to open ELF files from arbitrary location with name. 6 | 7 | package pfelf // import "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" 8 | 9 | // ELFOpener is the interface to open ELF files from arbitrary location with given filename. 10 | // 11 | // Implementations must be safe to be called from different threads simultaneously. 12 | type ELFOpener interface { 13 | OpenELF(string) (*File, error) 14 | } 15 | 16 | // SystemOpener implements ELFOpener by opening files from file system 17 | type systemOpener struct{} 18 | 19 | func (systemOpener) OpenELF(file string) (*File, error) { 20 | return Open(file) 21 | } 22 | 23 | var SystemOpener systemOpener 24 | -------------------------------------------------------------------------------- /libpf/pfelf/internal/mmap/mmap_test.go: -------------------------------------------------------------------------------- 1 | package mmap_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "testing" 8 | 9 | "go.opentelemetry.io/ebpf-profiler/libpf/pfelf/internal/mmap" 10 | ) 11 | 12 | func TestMmap_Subslice(t *testing.T) { 13 | f, err := os.CreateTemp(t.TempDir(), t.Name()+".testfile") 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | defer os.Remove(f.Name()) 18 | 19 | // Write some testData into the file. 20 | testData := "data-for-the-test" 21 | fmt.Fprintf(f, "%s", testData) 22 | 23 | mf, err := mmap.Open(f.Name()) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | defer mf.Close() 28 | 29 | t.Run("invalid subslice", func(t *testing.T) { 30 | // Try to access data out of scope from the data 31 | // in the backing file. 32 | _, err := mf.Subslice(1024, 1024) 33 | if !errors.Is(err, mmap.ErrInvalRequest) { 34 | t.Fatalf("expected %v but got %v", mmap.ErrInvalRequest, err) 35 | } 36 | }) 37 | 38 | t.Run("valid subslice", func(t *testing.T) { 39 | // Try to access data out within the scope of 40 | // len(testData). 41 | res, err := mf.Subslice(9, 8) 42 | if err != nil { 43 | t.Fatalf("expected no error but got %v", err) 44 | } 45 | if string(res) != testData[9:] { 46 | t.Fatalf("expected '%s' but got '%s'", testData[9:], string(res)) 47 | } 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /libpf/pfelf/reference.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // package pfelf implements functions for processing of ELF files and extracting data from 5 | // them. This file implements Reference which opens and caches a File on demand. 6 | 7 | package pfelf // import "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" 8 | 9 | // Reference is a reference to an ELF file which is loaded and cached on demand. 10 | type Reference struct { 11 | // Interface to open ELF files as needed 12 | ELFOpener 13 | 14 | // fileName is the full path of the ELF to open. 15 | fileName string 16 | 17 | // elfFile contains the cached ELF file 18 | elfFile *File 19 | } 20 | 21 | // NewReference returns a new Reference 22 | func NewReference(fileName string, elfOpener ELFOpener) *Reference { 23 | return &Reference{fileName: fileName, ELFOpener: elfOpener} 24 | } 25 | 26 | // FileName returns the file name associated with this Reference 27 | func (ref *Reference) FileName() string { 28 | return ref.fileName 29 | } 30 | 31 | // GetELF returns the File to access this File and keeps it cached. The 32 | // caller of this functions must not Close the File. 33 | func (ref *Reference) GetELF() (*File, error) { 34 | var err error 35 | if ref.elfFile == nil { 36 | ref.elfFile, err = ref.OpenELF(ref.fileName) 37 | } 38 | return ref.elfFile, err 39 | } 40 | 41 | // Close closes the File if it has been opened earlier. 42 | func (ref *Reference) Close() { 43 | if ref.elfFile != nil { 44 | ref.elfFile.Close() 45 | ref.elfFile = nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | *-debug-syms 2 | fixed-address 3 | the_notorious_build_id 4 | kernel-image 5 | ubuntu-kernel-image 6 | go-binary 7 | separate-debug-file 8 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | CC ?= cc 4 | OBJCOPY ?= objcopy 5 | 6 | BINARIES=fixed-address \ 7 | go-binary \ 8 | kernel-image \ 9 | separate-debug-file \ 10 | the_notorious_build_id \ 11 | ubuntu-kernel-image \ 12 | with-debug-syms \ 13 | without-debug-syms 14 | 15 | all: $(BINARIES) 16 | 17 | clean: 18 | rm -f $(BINARIES) 19 | 20 | with-debug-syms: test.c 21 | $(CC) $< -g -o $@ 22 | 23 | without-debug-syms: test.c 24 | $(CC) $< -s -o $@ 25 | 26 | separate-debug-file: with-debug-syms 27 | $(OBJCOPY) --only-keep-debug $< $@ 28 | 29 | fixed-address: fixed-address.c fixed-address.ld 30 | # The following command will likely print a warning (about a missing -T option), which should be ignored. 31 | # Removing the warning would require passing a fully-fledged linker script to bypass gcc's default. 32 | $(CC) $^ -o $@ 33 | 34 | # Write an ELF notes file with a build ID 35 | the_notorious_build_id: 36 | # \x04\x00\x00\x00: little endian for 4: the length of "GNU" + null character 37 | # \x14\x00\x00\x00: little endian for 20: the length of "_notorious_build_id_" 38 | # \x03\x00\x00\x00: little endian for 0x3 (Build ID note) 39 | bash -c "echo -en 'somedata\x04\x00\x00\x00\x14\x00\x00\x00\x03\x00\x00\x00GNU\x00_notorious_build_id_\x00somedata' > $@" 40 | 41 | kernel-image: test.c 42 | $(CC) $< -s -o $@ -DLINUX_VERSION="\"Linux version 1.2.3\\n\"" 43 | 44 | ubuntu-kernel-image: test.c 45 | $(CC) $< -s -o $@ -DLINUX_VERSION="\"Linux version 1.2.3 (Ubuntu 4.5.6)\\n\"" 46 | 47 | go-binary: gotest.go 48 | go build -o go-binary -ldflags "-w -s" gotest.go 49 | 50 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/fixed-address.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | __attribute__((section(".coffee_section"))) 5 | int function_at_fixed_address(void) { 6 | return 0; 7 | } 8 | 9 | int main(int argc, char *argv[]) { 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/fixed-address.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 0xC0FFEE0; 4 | .coffee_section : {} 5 | } 6 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/gotest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | } 5 | -------------------------------------------------------------------------------- /libpf/pfelf/testdata/test.c: -------------------------------------------------------------------------------- 1 | #ifndef LINUX_VERSION 2 | #define LINUX_VERSION "" 3 | #endif 4 | 5 | const char* version=LINUX_VERSION; // LINUX_VERSION 6 | 7 | int main(int argc, char *argv[]) { 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /libpf/pid.go: -------------------------------------------------------------------------------- 1 | package libpf // import "go.opentelemetry.io/ebpf-profiler/libpf" 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // PID represent Unix Process ID (pid_t) 8 | type PID uint32 9 | 10 | func (p PID) Hash32() uint32 { 11 | return uint32(p) 12 | } 13 | 14 | // PIDTID encodes a process id and a thread id 15 | type PIDTID uint64 16 | 17 | func (pt PIDTID) PID() PID { 18 | return PID(pt >> 32) 19 | } 20 | 21 | func (pt PIDTID) TID() PID { 22 | return PID(pt & 0xFFFFFFFF) 23 | } 24 | 25 | func (pt PIDTID) String() string { 26 | return fmt.Sprintf("PID: %v TID: %v", pt.PID(), pt.TID()) 27 | } 28 | -------------------------------------------------------------------------------- /libpf/readatbuf/readatbuf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package readatbuf_test 5 | 6 | import ( 7 | "bytes" 8 | "io" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/require" 12 | "go.opentelemetry.io/ebpf-profiler/libpf/readatbuf" 13 | "go.opentelemetry.io/ebpf-profiler/testsupport" 14 | ) 15 | 16 | func testVariant(t *testing.T, fileSize, granularity, cacheSize uint) { 17 | file := testsupport.GenerateTestInputFile(255, fileSize) 18 | rawReader := bytes.NewReader(file) 19 | cachingReader, err := readatbuf.New(rawReader, granularity, cacheSize) 20 | require.NoError(t, err) 21 | testsupport.ValidateReadAtWrapperTransparency(t, 10000, file, cachingReader) 22 | } 23 | 24 | func TestCaching(t *testing.T) { 25 | testVariant(t, 1024, 64, 1) 26 | testVariant(t, 1346, 11, 55) 27 | testVariant(t, 889, 34, 111) 28 | } 29 | 30 | func TestOutOfBoundsTail(t *testing.T) { 31 | buf := bytes.NewReader([]byte{0, 1, 2, 3, 4, 5, 6, 7}) 32 | r, err := readatbuf.New(buf, 5, 10) 33 | require.NoError(t, err) 34 | b := make([]byte, 1) 35 | for i := int64(0); i < 32; i++ { 36 | _, err = r.ReadAt(b, i) 37 | if i > 7 { 38 | require.ErrorIs(t, err, io.EOF) 39 | } else { 40 | require.NoError(t, err) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /libpf/xsync/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package xsync provides thin wrappers around locking primitives in an effort towards better 5 | // documenting the relationship between locks and the data they protect. 6 | package xsync // import "go.opentelemetry.io/ebpf-profiler/libpf/xsync" 7 | -------------------------------------------------------------------------------- /libpf/xsync/once.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package xsync // import "go.opentelemetry.io/ebpf-profiler/libpf/xsync" 5 | 6 | import ( 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | // NOTE: synchronization logic closely borrowed from sync.Once 12 | 13 | // Once is a lock that ensures that some data is initialized exactly once. 14 | // 15 | // Does not need explicit construction: simply do Once[MyType]{}. 16 | type Once[T any] struct { 17 | done atomic.Bool 18 | mu sync.Mutex 19 | data T 20 | } 21 | 22 | // GetOrInit the data protected by this lock. 23 | // 24 | // If the init function fails, the error is returned and the data is still 25 | // considered to be uninitialized. The init function will then be called 26 | // again on the next GetOrInit call. Only one thread will ever call init 27 | // at the same time. 28 | func (l *Once[T]) GetOrInit(init func() (T, error)) (*T, error) { 29 | if !l.done.Load() { 30 | // Outlined slow-path to allow inlining of the fast-path. 31 | return l.initSlow(init) 32 | } 33 | 34 | return &l.data, nil 35 | } 36 | 37 | func (l *Once[T]) initSlow(init func() (T, error)) (*T, error) { 38 | l.mu.Lock() 39 | defer l.mu.Unlock() 40 | 41 | // Contending call might have initialized while we waited for the lock. 42 | if l.done.Load() { 43 | return &l.data, nil 44 | } 45 | 46 | var err error 47 | l.data, err = init() 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | l.done.Store(true) 53 | return &l.data, err 54 | } 55 | 56 | // Get the previously initialized value. 57 | // 58 | // If the Once is not yet initialized, nil is returned. 59 | func (l *Once[T]) Get() *T { 60 | if !l.done.Load() { 61 | return nil 62 | } 63 | 64 | return &l.data 65 | } 66 | -------------------------------------------------------------------------------- /libpf/xsync/once_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package xsync_test 5 | 6 | import ( 7 | "errors" 8 | "strconv" 9 | "sync" 10 | "sync/atomic" 11 | "testing" 12 | "time" 13 | 14 | "github.com/stretchr/testify/assert" 15 | 16 | "go.opentelemetry.io/ebpf-profiler/libpf/xsync" 17 | ) 18 | 19 | func TestOnceLock(t *testing.T) { 20 | attempt := 0 // intentionally not atomic 21 | once := xsync.Once[string]{} 22 | someError := errors.New("oh no") 23 | numOk := atomic.Uint32{} 24 | wg := sync.WaitGroup{} 25 | 26 | assert.Nil(t, once.Get()) 27 | 28 | for i := 0; i < 32; i++ { 29 | wg.Add(1) 30 | 31 | go func() { 32 | val, err := once.GetOrInit(func() (string, error) { 33 | if attempt == 3 { 34 | time.Sleep(25 * time.Millisecond) 35 | return strconv.Itoa(attempt), nil 36 | } 37 | 38 | attempt++ 39 | return "", someError 40 | }) 41 | 42 | switch err { 43 | case someError: 44 | assert.Nil(t, val) 45 | case nil: 46 | numOk.Add(1) 47 | assert.Equal(t, "3", *val) 48 | default: 49 | assert.Fail(t, "unreachable") 50 | } 51 | 52 | wg.Done() 53 | }() 54 | } 55 | 56 | wg.Wait() 57 | assert.Equal(t, "3", *once.Get()) 58 | assert.Equal(t, uint32(32-3), numOk.Load()) 59 | } 60 | -------------------------------------------------------------------------------- /maccess/maccess.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package maccess provides functionality to check if a certain bug in 5 | // copy_from_user_nofault is patched. 6 | // 7 | // There were issues with the Linux kernel function copy_from_user_nofault that 8 | // caused systems to freeze. These issues were fixed with the following patch: 9 | // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d319f344561de23e810515d109c7278919bff7b0 10 | // 11 | //nolint:lll 12 | package maccess // import "go.opentelemetry.io/ebpf-profiler/maccess" 13 | -------------------------------------------------------------------------------- /metrics/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /* 5 | Package metrics contains the code for reporting metrics. 6 | 7 | # Directory Structure 8 | 9 | The current directory structure looks like 10 | 11 | metrics 12 | ├── doc.go // this file 13 | ├── genids/ 14 | │ └── main.go // tool to generate Go code from metrics.json 15 | ├── ids.go // autogenerated metric IDs 16 | ├── metrics.go // implement Add() and AddSlice() 17 | ├── metrics_test.go // tests the metrics package 18 | ├── metrics.json // list of known metrics 19 | └── types.go // definitions of Metric, MetricID, MetricValue 20 | */ 21 | package metrics // import "go.opentelemetry.io/ebpf-profiler/metrics" 22 | -------------------------------------------------------------------------------- /metrics/metrics_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package metrics 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // TestMetrics 13 | func TestMetrics(t *testing.T) { 14 | inputMetrics := []Metric{ 15 | {IDELFInfoCacheHit, MetricValue(33)}, 16 | {IDELFInfoCacheMiss, MetricValue(55)}, 17 | {IDErrProcESRCH, MetricValue(66)}, 18 | {IDErrProcNotExist, MetricValue(20)}, 19 | {IDUnwindCallInterpreter, MetricValue(0)}, 20 | } 21 | 22 | AddSlice(inputMetrics[0:2]) // 33, 55 23 | Add(inputMetrics[1].ID, inputMetrics[1].Value) // 55, dropped 24 | Add(inputMetrics[2].ID, inputMetrics[2].Value) // 66 25 | AddSlice(inputMetrics[3:4]) // 20 26 | Add(inputMetrics[0].ID, inputMetrics[0].Value) // 33, dropped 27 | AddSlice(inputMetrics[1:3]) // 55, 66 dropped 28 | AddSlice(inputMetrics[2:5]) // 66 dropped, 20 dropped, 0 dropped 29 | // Drop counter with 0 value as we don't expect it to appear in output 30 | inputMetrics = inputMetrics[:4] 31 | 32 | outputMetrics := make([]Metric, nMetrics) 33 | for j := range nMetrics { 34 | outputMetrics[j].ID = metricsBuffer[j].ID 35 | outputMetrics[j].Value = metricsBuffer[j].Value 36 | } 37 | assert.Equal(t, inputMetrics, outputMetrics) 38 | } 39 | 40 | func TestGetDefinitions(t *testing.T) { 41 | defs := GetDefinitions() 42 | assert.Greater(t, len(defs), 1) 43 | } 44 | -------------------------------------------------------------------------------- /metrics/types.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package metrics // import "go.opentelemetry.io/ebpf-profiler/metrics" 5 | 6 | // Create ids.go from metrics.json 7 | //go:generate go run genids/main.go metrics.json ids.go 8 | 9 | // MetricID is the type for metric IDs. 10 | type MetricID uint16 11 | 12 | // MetricValue is the type for metric values. 13 | type MetricValue int64 14 | 15 | // Metric is the type for a metric id/value pair. 16 | type Metric struct { 17 | ID MetricID 18 | Value MetricValue 19 | } 20 | 21 | // Summary helps summarizing metrics of the same ID from different sources before 22 | // processing it further. 23 | type Summary map[MetricID]MetricValue 24 | 25 | type MetricDefinition struct { 26 | ID MetricID `json:"id"` 27 | Type MetricType `json:"type"` 28 | Description string `json:"description"` 29 | Name string `json:"name"` 30 | Field string `json:"field"` 31 | Unit string `json:"unit"` 32 | Obsolete bool `json:"obsolete"` 33 | } 34 | 35 | type MetricType string 36 | 37 | const ( 38 | MetricTypeGauge MetricType = "gauge" 39 | MetricTypeCounter MetricType = "counter" 40 | ) 41 | -------------------------------------------------------------------------------- /nativeunwind/elfunwindinfo/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | helloworld 2 | helloworld.pie 3 | helloworld.stripped.pie 4 | helloworld.arm64 5 | -------------------------------------------------------------------------------- /nativeunwind/elfunwindinfo/testdata/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | BINARIES=helloworld \ 4 | helloworld.pie \ 5 | helloworld.stripped.pie \ 6 | helloworld.arm64 7 | 8 | # Use the default go executable if it is not specified otherwise. 9 | GO_BINARY ?= go 10 | 11 | all: $(BINARIES) 12 | 13 | clean: 14 | rm -f $(BINARIES) 15 | 16 | helloworld: 17 | $(GO_BINARY) build -o $@ helloworld.go 18 | 19 | helloworld.pie: 20 | $(GO_BINARY) build -buildmode=pie -o $@ helloworld.go 21 | 22 | helloworld.stripped.pie: 23 | $(GO_BINARY) build -buildmode=pie -ldflags="-s -w" -o $@ helloworld.go 24 | 25 | helloworld.arm64: 26 | GOARCH=arm64 $(GO_BINARY) build -o $@ helloworld.go 27 | -------------------------------------------------------------------------------- /nativeunwind/elfunwindinfo/testdata/helloworld.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | func sayHi() { 9 | fmt.Println("Hello World") 10 | } 11 | 12 | func main() { 13 | sayHi() 14 | } 15 | -------------------------------------------------------------------------------- /nativeunwind/elfunwindinfo/testdata/schrodinger-libpython3.8.so.1.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/nativeunwind/elfunwindinfo/testdata/schrodinger-libpython3.8.so.1.0 -------------------------------------------------------------------------------- /nativeunwind/elfunwindinfo/testdata/test.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/nativeunwind/elfunwindinfo/testdata/test.so -------------------------------------------------------------------------------- /nativeunwind/stackdeltaprovider.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package nativeunwind // import "go.opentelemetry.io/ebpf-profiler/nativeunwind" 5 | 6 | import ( 7 | "go.opentelemetry.io/ebpf-profiler/host" 8 | "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" 9 | sdtypes "go.opentelemetry.io/ebpf-profiler/nativeunwind/stackdeltatypes" 10 | ) 11 | 12 | type Statistics struct { 13 | // Number of times of successful extractions. 14 | Success uint64 15 | 16 | // Number of times extracting stack deltas failed. 17 | ExtractionErrors uint64 18 | } 19 | 20 | // StackDeltaProvider defines an interface for types that provide access to the stack deltas from 21 | // executables. 22 | type StackDeltaProvider interface { 23 | // GetIntervalStructuresForFile inspects a single executable and extracts data that is needed 24 | // to rebuild the stack for traces of this executable. 25 | GetIntervalStructuresForFile(fileID host.FileID, elfRef *pfelf.Reference, 26 | interval *sdtypes.IntervalData) error 27 | 28 | // GetAndResetStatistics returns the internal statistics for this provider and resets all 29 | // values to 0. 30 | GetAndResetStatistics() Statistics 31 | } 32 | -------------------------------------------------------------------------------- /nopanicslicereader/nopanicslicereader_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package nopanicslicereader 5 | 6 | import ( 7 | "testing" 8 | 9 | "go.opentelemetry.io/ebpf-profiler/libpf" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestSliceReader(t *testing.T) { 15 | data := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} 16 | assert.Equal(t, uint16(0x0403), Uint16(data, 2)) 17 | assert.Equal(t, uint16(0), Uint16(data, 7)) 18 | assert.Equal(t, uint32(0x04030201), Uint32(data, 0)) 19 | assert.Equal(t, uint32(0), Uint32(data, 100)) 20 | assert.Equal(t, uint64(0x0807060504030201), Uint64(data, 0)) 21 | assert.Equal(t, uint64(0), Uint64(data, 1)) 22 | assert.Equal(t, libpf.Address(0x0807060504030201), Ptr(data, 0)) 23 | assert.Equal(t, libpf.Address(0x08070605), PtrDiff32(data, 4)) 24 | } 25 | -------------------------------------------------------------------------------- /pacmask/pacmask_arm64.s: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // func PACIA(ptr, modifier uint64) uint64; 4 | // 5 | // This particular implementation of this intrinsic uses the `paciasp` 6 | // instruction rather than the actual `pacia` instruction, even if that makes 7 | // the implementation more complex due to the required register shuffling. The 8 | // reason here is that `paciasp` is encoded in a space that was previously a 9 | // `nop`, meaning that it is backward compatible to devices without PAC support. 10 | // This isn't the case for the more generic `pacia` instruction. 11 | TEXT ·PACIA(SB),$0-16 12 | // Backup original LR and SP. 13 | MOVD LR, R1 14 | MOVD RSP, R2 15 | 16 | // Move `ptr` into LR 17 | MOVD ptr+0(FP), LR 18 | 19 | // Move `modifier` into SP. 20 | MOVD modifier+8(FP), R0 21 | MOVD R0, RSP 22 | 23 | // `PACIASP` instruction. Go assembler doesn't support it yet. 24 | WORD $0xD503233F 25 | 26 | // Temporarily place PAC'ed LR into X0, since the stack ptr isn't restored, yet. 27 | MOVD LR, R0 28 | 29 | // Restore original SP and LR. 30 | MOVD R2, RSP 31 | MOVD R1, LR 32 | 33 | // Place the return value on stack. 34 | MOVD R0, r1+16(FP) 35 | 36 | RET 37 | -------------------------------------------------------------------------------- /pacmask/pacmask_other.go: -------------------------------------------------------------------------------- 1 | //go:build !arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package pacmask // import "go.opentelemetry.io/ebpf-profiler/pacmask" 7 | 8 | // GetPACMask always returns 0 on this platform. 9 | func GetPACMask() uint64 { 10 | return 0 11 | } 12 | -------------------------------------------------------------------------------- /proc/testdata/kallsyms: -------------------------------------------------------------------------------- 1 | 0000000000000000 A fixed_percpu_data 2 | 0000000000000000 A __per_cpu_start 3 | 0000000000001000 A cpu_debug_store 4 | 0000000000002000 A irq_stack_backing_store 5 | 0000000000006000 A cpu_tss_rw 6 | ffffffffc0346f40 t hidraw_connect [hid] 7 | ffffffffc0340470 t hidinput_find_field [hid] 8 | ffffffffc033d150 t hid_parse_report [hid] 9 | ffffffffc033f9a0 t hid_open_report [hid] 10 | ffffffffc03459b0 t hid_quirks_init [hid] 11 | ffffffffc0345720 t hid_ignore [hid] 12 | ffffffffc033e550 t hid_add_device [hid] 13 | ffffffffc0346e20 t hidraw_report_event [hid] 14 | -------------------------------------------------------------------------------- /proc/testdata/kallsyms_0: -------------------------------------------------------------------------------- 1 | 0000000000000000 A fixed_percpu_data 2 | 0000000000000000 A __per_cpu_start 3 | 0000000000000000 A cpu_debug_store 4 | 0000000000000000 A irq_stack_backing_store 5 | 0000000000000000 A cpu_tss_rw 6 | -------------------------------------------------------------------------------- /proc/testdata/kallsyms_invalid: -------------------------------------------------------------------------------- 1 | 0000000000000000 A fixed_percpu_data 2 | 0000000000000000 A __per_cpu_start 3 | 0000000000001000 A cpu_debug_store 4 | 0000000000002000 irq_stack_backing_store 5 | 0000000000006000 A cpu_tss_rw 6 | -------------------------------------------------------------------------------- /process/debug_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package process // import "go.opentelemetry.io/ebpf-profiler/process" 7 | 8 | import ( 9 | "debug/elf" 10 | "encoding/binary" 11 | "fmt" 12 | ) 13 | 14 | const currentMachine = elf.EM_X86_64 15 | 16 | func (sp *ptraceProcess) getThreadInfo(tid int) (ThreadInfo, error) { 17 | prStatus := make([]byte, 28*8) 18 | if err := ptraceGetRegset(tid, int(elf.NT_PRSTATUS), prStatus); err != nil { 19 | return ThreadInfo{}, fmt.Errorf("failed to get LWP %d thread info: %v", tid, err) 20 | } 21 | return ThreadInfo{ 22 | LWP: uint32(tid), 23 | GPRegs: prStatus, 24 | TPBase: binary.LittleEndian.Uint64(prStatus[21*8:]), 25 | }, nil 26 | } 27 | -------------------------------------------------------------------------------- /process/debug_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package process // import "go.opentelemetry.io/ebpf-profiler/process" 7 | 8 | import ( 9 | "debug/elf" 10 | "encoding/binary" 11 | "fmt" 12 | ) 13 | 14 | const currentMachine = elf.EM_AARCH64 15 | 16 | func (sp *ptraceProcess) GetMachineData() MachineData { 17 | pacMask := make([]byte, 16) 18 | _ = ptraceGetRegset(int(sp.pid), int(NT_ARM_PAC_MASK), pacMask) 19 | 20 | return MachineData{ 21 | Machine: elf.EM_AARCH64, 22 | DataPACMask: binary.LittleEndian.Uint64(pacMask[0:8]), 23 | CodePACMask: binary.LittleEndian.Uint64(pacMask[8:16]), 24 | } 25 | } 26 | 27 | func (sp *ptraceProcess) getThreadInfo(tid int) (ThreadInfo, error) { 28 | prStatus := make([]byte, 35*8) 29 | if err := ptraceGetRegset(tid, int(elf.NT_PRSTATUS), prStatus); err != nil { 30 | return ThreadInfo{}, fmt.Errorf("failed to get LWP %d thread info: %v", tid, err) 31 | } 32 | // Treat TLS base reading error as non-fatal 33 | armTLS := make([]byte, 8) 34 | _ = ptraceGetRegset(tid, int(NT_ARM_TLS), armTLS) 35 | 36 | return ThreadInfo{ 37 | LWP: uint32(tid), 38 | GPRegs: prStatus, 39 | TPBase: binary.LittleEndian.Uint64(armTLS), 40 | }, nil 41 | } 42 | -------------------------------------------------------------------------------- /processmanager/ebpf/ebpf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ebpf 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | "go.opentelemetry.io/ebpf-profiler/support" 13 | ) 14 | 15 | func TestMapID(t *testing.T) { 16 | testCases := map[uint32]uint16{ 17 | 0: 8, 18 | 1: 8, 19 | 2: 8, 20 | 0xFF: 8, // 255 21 | 0x100: 9, // 256 22 | 0x1FF: 9, // 511 23 | 0x200: 10, // 512 24 | 0x3FF: 10, // 1023 25 | 0x400: 11, // 1024 26 | 0xFFFFF: 20, // 1048575 (2^20 - 1) 27 | (1 << support.StackDeltaBucketLargest) - 1: support.StackDeltaBucketLargest, 28 | } 29 | for numStackDeltas, expectedShift := range testCases { 30 | numStackDeltas := numStackDeltas 31 | expectedShift := expectedShift 32 | t.Run(fmt.Sprintf("deltas %d", numStackDeltas), func(t *testing.T) { 33 | shift, err := getMapID(numStackDeltas) 34 | require.NoError(t, err) 35 | assert.Equal(t, expectedShift, shift, "wrong map name for %d deltas", 36 | numStackDeltas) 37 | }) 38 | } 39 | 40 | _, err := getMapID(1 << (support.StackDeltaBucketLargest + 1)) 41 | require.Error(t, err) 42 | } 43 | -------------------------------------------------------------------------------- /processmanager/ebpf/types.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ebpf // import "go.opentelemetry.io/ebpf-profiler/processmanager/ebpf" 5 | 6 | // StackDeltaEBPF represents stack deltas preprocessed by the ProcessManager which are 7 | // then loaded to the eBPF map. This is Go equivalent of 'struct StackDelta' in eBPF types.h. 8 | // See the eBPF header file for details. 9 | type StackDeltaEBPF struct { 10 | AddressLow uint16 11 | UnwindInfo uint16 12 | } 13 | -------------------------------------------------------------------------------- /processmanager/synthdeltas_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" 7 | 8 | var createVDSOSyntheticRecord = createVDSOSyntheticRecordArm64 9 | -------------------------------------------------------------------------------- /processmanager/synthdeltas_other.go: -------------------------------------------------------------------------------- 1 | //go:build !arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" 7 | 8 | var createVDSOSyntheticRecord = createVDSOSyntheticRecordNone 9 | -------------------------------------------------------------------------------- /processmanager/synthdeltas_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package processmanager // import "go.opentelemetry.io/ebpf-profiler/processmanager" 5 | 6 | import ( 7 | "testing" 8 | 9 | "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" 10 | sdtypes "go.opentelemetry.io/ebpf-profiler/nativeunwind/stackdeltatypes" 11 | "go.opentelemetry.io/ebpf-profiler/support" 12 | 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | func TestVDSOArm64(t *testing.T) { 17 | frameSize16 := sdtypes.UnwindInfo{ 18 | Opcode: support.UnwindOpcodeBaseFP, 19 | Param: 16, 20 | FPOpcode: support.UnwindOpcodeBaseFP, 21 | FPParam: 8, 22 | } 23 | 24 | testCases := map[string]sdtypes.StackDeltaArray{ 25 | "vdso.arch64.withframe": { 26 | {Address: 0, Info: sdtypes.UnwindInfoLR}, 27 | {Address: 0x7d8, Info: frameSize16}, 28 | {Address: 0x7e4, Info: sdtypes.UnwindInfoLR}, 29 | {Address: 0x800, Info: frameSize16}, 30 | {Address: 0x80c, Info: sdtypes.UnwindInfoLR}, 31 | {Address: 0x8f8, Info: sdtypes.UnwindInfoSignal}, 32 | {Address: 0x900, Info: sdtypes.UnwindInfoLR}, 33 | }, 34 | } 35 | 36 | for name, expected := range testCases { 37 | t.Run(name, func(t *testing.T) { 38 | ef, err := pfelf.Open("testdata/" + name) 39 | require.NoError(t, err) 40 | defer ef.Close() 41 | 42 | deltas := createVDSOSyntheticRecordArm64(ef) 43 | require.Equal(t, expected, deltas.Deltas, "vdso deltas wrong") 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /processmanager/testdata/vdso.arch64.withframe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/processmanager/testdata/vdso.arch64.withframe -------------------------------------------------------------------------------- /remotememory/remotememory_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package remotememory 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | "os" 10 | "syscall" 11 | "testing" 12 | "unsafe" 13 | 14 | "github.com/stretchr/testify/assert" 15 | "github.com/stretchr/testify/require" 16 | 17 | "go.opentelemetry.io/ebpf-profiler/libpf" 18 | ) 19 | 20 | func RemoteMemTests(t *testing.T, rm RemoteMemory) { 21 | data := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} 22 | dataPtr := libpf.Address(uintptr(unsafe.Pointer(&data[0]))) 23 | str := []byte("this is a string\x00") 24 | strPtr := libpf.Address(uintptr(unsafe.Pointer(&str[0]))) 25 | longStr := append(bytes.Repeat([]byte("long test string"), 4095/16), 0x00) 26 | longStrPtr := libpf.Address(uintptr(unsafe.Pointer(&longStr[0]))) 27 | 28 | foo := make([]byte, len(data)) 29 | err := rm.Read(libpf.Address(uintptr(unsafe.Pointer(&data))), foo) 30 | if errors.Is(err, syscall.ENOSYS) { 31 | t.Skipf("skipping due to error: %v", err) 32 | } 33 | require.NoError(t, err) 34 | assert.Equal(t, uint32(0x04030201), rm.Uint32(dataPtr)) 35 | assert.Equal(t, libpf.Address(0x0807060504030201), rm.Ptr(dataPtr)) 36 | assert.Equal(t, string(str[:len(str)-1]), rm.String(strPtr)) 37 | assert.Equal(t, string(longStr[:len(longStr)-1]), rm.String(longStrPtr)) 38 | } 39 | 40 | func TestProcessVirtualMemory(t *testing.T) { 41 | RemoteMemTests(t, NewProcessVirtualMemory(libpf.PID(os.Getpid()))) 42 | } 43 | -------------------------------------------------------------------------------- /reporter/runloop.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" 5 | 6 | import ( 7 | "context" 8 | "time" 9 | 10 | "go.opentelemetry.io/ebpf-profiler/libpf" 11 | ) 12 | 13 | // runLoop implements the run loop for all reporters 14 | type runLoop struct { 15 | // stopSignal is the stop signal for shutting down all background tasks. 16 | stopSignal chan libpf.Void 17 | } 18 | 19 | func (rl *runLoop) Start(ctx context.Context, reportInterval time.Duration, run, purge func()) { 20 | go func() { 21 | tick := time.NewTicker(reportInterval) 22 | defer tick.Stop() 23 | purgeTick := time.NewTicker(5 * time.Minute) 24 | defer purgeTick.Stop() 25 | 26 | for { 27 | select { 28 | case <-ctx.Done(): 29 | return 30 | case <-rl.stopSignal: 31 | return 32 | case <-tick.C: 33 | run() 34 | tick.Reset(libpf.AddJitter(reportInterval, 0.2)) 35 | case <-purgeTick.C: 36 | purge() 37 | } 38 | } 39 | }() 40 | } 41 | 42 | func (rl *runLoop) Stop() { 43 | close(rl.stopSignal) 44 | } 45 | -------------------------------------------------------------------------------- /reporter/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /reporter/testdata/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | CC ?= cc 4 | CFLAGS = -Wl,--build-id 5 | 6 | all: test 7 | 8 | clean: 9 | rm -f test 10 | 11 | test: test.c 12 | $(CC) $(CFLAGS) $< -g -o $@ 13 | -------------------------------------------------------------------------------- /reporter/testdata/test.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | // This process must not return (tests depend on it) 8 | return pause(); 9 | } 10 | -------------------------------------------------------------------------------- /reporter/times.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" 5 | 6 | import ( 7 | "time" 8 | 9 | "go.opentelemetry.io/ebpf-profiler/times" 10 | ) 11 | 12 | // Compile time check to make sure config.Times satisfies the interfaces. 13 | var _ Times = (*times.Times)(nil) 14 | 15 | // Times is a subset of config.IntervalsAndTimers. 16 | type Times interface { 17 | ReportInterval() time.Duration 18 | GRPCConnectionTimeout() time.Duration 19 | GRPCOperationTimeout() time.Duration 20 | GRPCStartupBackoffTime() time.Duration 21 | GRPCAuthErrorDelay() time.Duration 22 | } 23 | -------------------------------------------------------------------------------- /reporter/util.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package reporter // import "go.opentelemetry.io/ebpf-profiler/reporter" 5 | 6 | import "github.com/zeebo/xxh3" 7 | 8 | // hashString is a helper function for LRUs that use string as a key. 9 | // Xxh3 turned out to be the fastest hash function for strings in the FreeLRU benchmarks. 10 | // It was only outperformed by the AES hash function, which is implemented in Plan9 assembly. 11 | func hashString(s string) uint32 { 12 | return uint32(xxh3.HashString(s)) 13 | } 14 | -------------------------------------------------------------------------------- /rlimit/rlimit.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package rlimit // import "go.opentelemetry.io/ebpf-profiler/rlimit" 5 | 6 | import ( 7 | "fmt" 8 | 9 | "golang.org/x/sys/unix" 10 | 11 | log "github.com/sirupsen/logrus" 12 | ) 13 | 14 | // MaximizeMemlock updates the memlock resource limit to RLIM_INFINITY. 15 | // It returns a function to reset the resource limit to its original value or an error. 16 | func MaximizeMemlock() (func(), error) { 17 | var oldLimit unix.Rlimit 18 | tmpLimit := unix.Rlimit{ 19 | Cur: unix.RLIM_INFINITY, 20 | Max: unix.RLIM_INFINITY, 21 | } 22 | 23 | if err := unix.Prlimit(0, unix.RLIMIT_MEMLOCK, &tmpLimit, &oldLimit); err != nil { 24 | return nil, fmt.Errorf("failed to set temporary rlimit: %w", err) 25 | } 26 | 27 | return func() { 28 | if err := unix.Setrlimit(unix.RLIMIT_MEMLOCK, &oldLimit); err != nil { 29 | log.Fatalf("Failed to set old rlimit: %v", err) 30 | } 31 | }, nil 32 | } 33 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/.gitignore: -------------------------------------------------------------------------------- 1 | c/demo 2 | go/go 3 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "symblib-capi" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | license.workspace = true 7 | 8 | [lib] 9 | crate-type = ["staticlib"] 10 | 11 | [dependencies] 12 | symblib.path = "../symblib" 13 | 14 | fallible-iterator.workspace = true 15 | thiserror.workspace = true 16 | 17 | [build-dependencies] 18 | serde_json = "1.0.140" 19 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/README.md: -------------------------------------------------------------------------------- 1 | symblib C API 2 | ============= 3 | 4 | This crate exposes the public core API of symblib as a C library. 5 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/c/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean run-demo 2 | 3 | RUST_WORKSPACE_DIR = ../../.. 4 | TARGET_DIR = $(RUST_WORKSPACE_DIR)/target/release 5 | 6 | all: demo 7 | 8 | $(TARGET_DIR)/libsymblib_capi.so: ../src/*.rs 9 | cargo build --release --manifest-path $(RUST_WORKSPACE_DIR)/Cargo.toml 10 | 11 | demo: symblib.h demo.c $(TARGET_DIR)/libsymblib_capi.so 12 | cc -g -I. -o $@ demo.c -L$(TARGET_DIR) -lsymblib_capi -ldl 13 | 14 | run-demo: demo 15 | LD_LIBRARY_PATH=$(TARGET_DIR) ./demo 16 | 17 | clean: 18 | cargo clean --manifest-path $(RUST_CRATE_DIR)/Cargo.toml 19 | rm -f demo 20 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/go/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | all: 4 | CGO_ENABLED=1 \ 5 | go build \ 6 | -mod=readonly \ 7 | -ldflags='-linkmode external -extldflags=-static' \ 8 | -trimpath \ 9 | -tags 'static_build' 10 | 11 | 12 | clean: 13 | go clean 14 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/src/ffistr.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use std::ffi::{c_char, CString}; 5 | use std::{mem, ptr}; 6 | 7 | /// Read-only, nullable, owned FFI-safe string type. 8 | #[derive(Debug)] 9 | #[repr(transparent)] 10 | pub struct SymblibString(*mut c_char); 11 | 12 | impl From> for SymblibString { 13 | fn from(maybe_str: Option) -> Self { 14 | match maybe_str { 15 | Some(s) => s.into(), 16 | None => SymblibString(ptr::null_mut()), 17 | } 18 | } 19 | } 20 | 21 | impl From for SymblibString { 22 | fn from(x: String) -> Self { 23 | Self(unsafe { CString::from_vec_unchecked(x.into_bytes()).into_raw() }) 24 | } 25 | } 26 | 27 | impl From for Option { 28 | fn from(maybe_str: SymblibString) -> Self { 29 | if maybe_str.0.is_null() { 30 | None 31 | } else { 32 | let cstr = unsafe { CString::from_raw(maybe_str.0) }; 33 | mem::forget(maybe_str); 34 | Some(cstr.into_string().unwrap()) 35 | } 36 | } 37 | } 38 | 39 | impl Drop for SymblibString { 40 | fn drop(&mut self) { 41 | if !self.0.is_null() { 42 | drop(unsafe { CString::from_raw(self.0 as _) }); 43 | self.0 = ptr::null_mut(); 44 | } 45 | } 46 | } 47 | 48 | unsafe impl Send for SymblibString {} 49 | -------------------------------------------------------------------------------- /rust-crates/symblib-capi/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![doc = include_str!("../README.md")] 5 | 6 | mod ffislice; 7 | mod ffistr; 8 | mod gosym; 9 | mod pointresolver; 10 | mod rangeextr; 11 | mod retpadextr; 12 | mod status; 13 | 14 | pub use ffislice::*; 15 | pub use ffistr::*; 16 | pub use gosym::*; 17 | pub use pointresolver::*; 18 | pub use rangeextr::*; 19 | pub use retpadextr::*; 20 | pub use status::*; 21 | -------------------------------------------------------------------------------- /rust-crates/symblib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "symblib" 3 | edition = "2021" 4 | version.workspace = true 5 | rust-version.workspace = true 6 | license.workspace = true 7 | 8 | [dependencies] 9 | base64.workspace = true 10 | cpp_demangle.workspace = true 11 | fallible-iterator.workspace = true 12 | flate2.workspace = true 13 | gimli.workspace = true 14 | intervaltree.workspace = true 15 | lru.workspace = true 16 | memmap2.workspace = true 17 | object.workspace = true 18 | prost.workspace = true 19 | rustc-demangle.workspace = true 20 | sha2.workspace = true 21 | smallvec.workspace = true 22 | tempfile.workspace = true 23 | thiserror.workspace = true 24 | zstd.workspace = true 25 | zydis.workspace = true 26 | 27 | [build-dependencies] 28 | prost-build.workspace = true 29 | -------------------------------------------------------------------------------- /rust-crates/symblib/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | static PROTO: &str = "../symb-proto/symbfile.proto"; 5 | 6 | fn main() -> Result<(), Box> { 7 | println!("cargo:rerun-if-changed={PROTO}"); 8 | Ok(prost_build::compile_protos( 9 | &[PROTO], 10 | &["../symb-proto"], 11 | )?) 12 | } 13 | -------------------------------------------------------------------------------- /rust-crates/symblib/src/dbglog.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Minimal debug logging support. 5 | //! 6 | //! If we end up needing more elaborate logging later, it is worth considering 7 | //! switching to the `log` crate and a corresponding subscriber. However, for 8 | //! our current needs this seemed overkill. 9 | 10 | use std::sync::atomic::AtomicBool; 11 | 12 | // Re-export to make the macro show up in this module in rustdoc. 13 | pub use crate::debug; 14 | 15 | /// Determines whether [`debug`] messages are actually printed or not. 16 | pub static ENABLED: AtomicBool = AtomicBool::new(false); 17 | 18 | /// Print to stderr if debug printing is enabled. 19 | /// 20 | /// See [`eprintln`] documentation for usage. 21 | #[macro_export] 22 | macro_rules! debug { 23 | ( $($args:tt)* ) => { 24 | if $crate::dbglog::ENABLED.load(::std::sync::atomic::Ordering::Relaxed) { 25 | ::std::eprintln!( $($args)* ); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust-crates/symblib/src/gosym/errors.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use super::*; 5 | 6 | /// Result type shorthand. 7 | pub type Result = std::result::Result; 8 | 9 | /// Errors that can occur during parsing. 10 | #[non_exhaustive] 11 | #[allow(missing_docs)] 12 | #[derive(Debug, thiserror::Error)] 13 | pub enum Error { 14 | #[error("Unable to find gopclntab")] 15 | GopclntabNotFound, 16 | 17 | #[error("Unable to find module data")] 18 | ModuleDataNotFound, 19 | 20 | #[error("Unable to find code section (`.text`)")] 21 | CodeSectionNotFound, 22 | 23 | #[error("Unable to resolve the destination of the gofunc pointer")] 24 | BadGoFuncPtr, 25 | 26 | #[error("Found pointer to invalid memory")] 27 | InvalidPtr, 28 | 29 | #[error("Go symbols section is malformed")] 30 | MalformedGopclntab, 31 | 32 | #[error("Go version is not supported")] 33 | UnsupportedGoVersion, 34 | 35 | #[error("Inline index is malformed")] 36 | BadInlineIndex, 37 | 38 | #[error("File index is malformed")] 39 | BadFileIndex, 40 | 41 | #[error("Line number is malformed")] 42 | BadLineNumber, 43 | 44 | #[error("Unexpected end of file")] 45 | UnexpectedEof, 46 | 47 | #[error("Encountered non-utf8 string")] 48 | NonUtf8String, 49 | 50 | #[error("Variable length integer is too big")] 51 | VarIntTooLong, 52 | 53 | #[error("Unable to read section without copying")] 54 | CannotAvoidCopy, 55 | 56 | #[error("Reader currently doesn't support big endian binaries")] 57 | BigEndian, 58 | 59 | #[error("objfile error: {}", .0)] 60 | Objfile(#[from] objfile::Error), 61 | } 62 | -------------------------------------------------------------------------------- /rust-crates/symblib/src/gosym/raw/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Provides decoding of the raw data structures. 5 | 6 | mod reader; 7 | mod regions; 8 | mod structs; 9 | mod types; 10 | 11 | // Re-export some stuff that is needed across all `raw` submodules. 12 | use super::{Error, Result, Version}; 13 | use crate::VirtAddr; 14 | 15 | pub use reader::*; 16 | pub use regions::*; 17 | pub use structs::*; 18 | pub use types::*; 19 | -------------------------------------------------------------------------------- /rust-crates/symblib/src/symbconv/obj.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Translates object file (e.g. ELF) symbols into a range symbfile. 5 | 6 | use super::{Error, RangeExtractor, RangeVisitor, Result, Stats}; 7 | use crate::{demangle, objfile, symbfile}; 8 | 9 | /// Extracts ranges from object file symbols. 10 | pub struct Extractor<'obj> { 11 | obj: &'obj objfile::Reader<'obj>, 12 | source: objfile::SymbolSource, 13 | } 14 | 15 | impl<'obj> Extractor<'obj> { 16 | /// Create a new object file symbol extractor. 17 | pub fn new(obj: &'obj objfile::Reader<'obj>, source: objfile::SymbolSource) -> Self { 18 | Self { obj, source } 19 | } 20 | } 21 | 22 | impl<'obj> RangeExtractor for Extractor<'obj> { 23 | fn extract(&self, visitor: RangeVisitor<'_>) -> Result> { 24 | for sym in self.obj.function_symbols(self.source) { 25 | let rng = obj_symbol_to_range(&sym); 26 | visitor(rng).map_err(Error::Obj)?; 27 | } 28 | 29 | Ok(None) 30 | } 31 | } 32 | 33 | /// Translate an object file symbol to a range. 34 | fn obj_symbol_to_range(sym: &objfile::Symbol<'_>) -> symbfile::Range { 35 | symbfile::Range { 36 | elf_va: sym.virt_addr, 37 | length: sym.length as u32, 38 | func: demangle::demangle(sym.name).into_owned(), 39 | file: None, 40 | call_file: None, 41 | call_line: None, 42 | depth: 0, 43 | line_table: Default::default(), 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rust-crates/symblib/src/symbfile/proto.rs: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Raw protobuf message definitions. 5 | 6 | #![allow(missing_docs)] 7 | 8 | // Simply include protobuf definitions generated by `build.rs`. 9 | include!(concat!(env!("OUT_DIR"), "/symbfile.rs")); 10 | -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: inline inline-compressed-dwarf inline-split-dwarf inline-big-fake-compressed-dwarf \ 2 | inline-no-tco clean inline-compressed-dwarf-zstd go-toolchains 3 | 4 | all: inline inline-compressed-dwarf inline-split-dwarf inline-big-fake-compressed-dwarf \ 5 | inline-no-tco inline-compressed-dwarf-zstd go-toolchains 6 | 7 | inline: inline.c 8 | cc $< -o $@ -O2 -g 9 | 10 | inline-no-tco: inline.c 11 | cc $< -o $@ -O2 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls 12 | 13 | inline-compressed-dwarf: inline 14 | objcopy --compress-debug-sections=zlib $< $@ 15 | 16 | inline-compressed-dwarf-zstd: inline 17 | objcopy --compress-debug-sections=zstd $< $@ 18 | 19 | inline-big-fake-compressed-dwarf: inline 20 | dd if=/dev/zero bs=4M count=16 of=/tmp/big-fake-dwarf 21 | # objcopy only supports compressing DWARF sections, not arbitrary ones, 22 | # so we swap a DWARF section here to work around that limitation 23 | objcopy --update-section .debug_info=/tmp/big-fake-dwarf $< $@ 24 | objcopy --compress-debug-sections $@ 25 | 26 | inline-split-dwarf: inline 27 | cp inline inline-split-dwarf 28 | dwz -M meow -m inline-split-dwarf.dwp inline-split-dwarf inline-split-dwarf 29 | 30 | go-toolchains: 31 | GOTOOLCHAIN=go1.20.14 go build -o go-1.20.14 main.go 32 | GOTOOLCHAIN=go1.22.12 go build -o go-1.22.12 main.go 33 | GOTOOLCHAIN=go1.24.0 go build -o go-1.24.0 main.go 34 | 35 | clean: 36 | echo "not deleting anything: executables are meant to be kept under VC" 37 | -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/README.md: -------------------------------------------------------------------------------- 1 | Executables here are intentionally kept in VC to allow tests to hard-code aspects like text 2 | section sizes and build IDs to validate their parsing. -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/go-1.20.14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/go-1.20.14 -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/go-1.22.12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/go-1.22.12 -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/go-1.24.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/go-1.24.0 -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/open-telemetry/opentelemetry-ebpf-profiler/rust-crates/symblib/testdata 2 | 3 | go 1.20 4 | -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-big-fake-compressed-dwarf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-big-fake-compressed-dwarf -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-compressed-dwarf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-compressed-dwarf -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-compressed-dwarf-zstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-compressed-dwarf-zstd -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-no-tco: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-no-tco -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-no-tco.ranges.symbfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-no-tco.ranges.symbfile -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-split-dwarf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-split-dwarf -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline-split-dwarf.dwp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/rust-crates/symblib/testdata/inline-split-dwarf.dwp -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/inline.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | 6 | #define NOINLINE __attribute__((noinline)) 7 | #define INLINE static inline __attribute__((always_inline)) 8 | 9 | NOINLINE int d() { 10 | printf("hello!\n"); 11 | } 12 | 13 | NOINLINE int c() { 14 | d(); 15 | } 16 | 17 | NOINLINE int b() { 18 | c(); 19 | } 20 | 21 | NOINLINE int a() { 22 | b(); 23 | } 24 | 25 | INLINE int d_inline() { 26 | printf("hello!\n"); 27 | } 28 | 29 | INLINE int c_inline() { 30 | d_inline(); 31 | } 32 | 33 | INLINE int b_inline() { 34 | c_inline(); 35 | } 36 | 37 | INLINE int a_inline() { 38 | b_inline(); 39 | } 40 | 41 | NOINLINE int main() { 42 | a(); 43 | a_inline(); 44 | } 45 | -------------------------------------------------------------------------------- /rust-crates/symblib/testdata/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("Hello, 世界") 7 | } 8 | -------------------------------------------------------------------------------- /support/.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | ebpf/tracer.ebpf.debug.amd64 3 | ebpf/tracer.ebpf.debug.arm64 4 | -------------------------------------------------------------------------------- /support/debugtracer_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && debugtracer 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | import ( 9 | _ "embed" 10 | ) 11 | 12 | //go:embed ebpf/tracer.ebpf.debug.amd64 13 | var debugTracerData []byte 14 | -------------------------------------------------------------------------------- /support/debugtracer_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 && debugtracer 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | import ( 9 | _ "embed" 10 | ) 11 | 12 | //go:embed ebpf/tracer.ebpf.debug.arm64 13 | var debugTracerData []byte 14 | -------------------------------------------------------------------------------- /support/debugtracer_dummy.go: -------------------------------------------------------------------------------- 1 | //go:build !debugtracer 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | // debugtracer_dummy.go satisfies build requirements where the eBPF debug tracers 9 | // file does not exist. 10 | var debugTracerData []byte 11 | -------------------------------------------------------------------------------- /support/ebpf/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AlignAfterOpenBracket: AlwaysBreak 3 | AllowShortFunctionsOnASingleLine: Inline 4 | BinPackArguments: false 5 | BinPackParameters: false 6 | BraceWrapping: 7 | AfterFunction: true 8 | SplitEmptyFunction: false 9 | BreakBeforeBraces: Custom 10 | BreakStringLiterals: false 11 | ColumnLimit: 100 12 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 13 | IndentPPDirectives: BeforeHash 14 | AlignConsecutiveMacros: AcrossComments 15 | AlignConsecutiveAssignments: AcrossComments 16 | AllowShortCaseLabelsOnASingleLine: true 17 | ContinuationIndentWidth: 2 18 | -------------------------------------------------------------------------------- /support/ebpf/bpf_map.h: -------------------------------------------------------------------------------- 1 | #ifndef OPTI_BPF_MAP_H 2 | #define OPTI_BPF_MAP_H 3 | 4 | // bpf_map_def is a custom struct we use to define eBPF maps. It is not used by 5 | // the kernel, but by the ebpf loader (kernel tools, gobpf, cilium-ebpf, etc.). 6 | // This version matches with cilium-ebpf. 7 | 8 | typedef struct bpf_map_def { 9 | unsigned int type; 10 | unsigned int key_size; 11 | unsigned int value_size; 12 | unsigned int max_entries; 13 | unsigned int map_flags; 14 | unsigned int pinning; 15 | } bpf_map_def; 16 | 17 | #endif // OPTI_BPF_MAP_H 18 | -------------------------------------------------------------------------------- /support/ebpf/print_instruction_count.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | export SHELLOPTS 7 | 8 | file="$1" 9 | 10 | OBJDUMP_CMD=llvm-objdump 11 | if ! type -p "${OBJDUMP_CMD}"; then 12 | OBJDUMP_CMD=llvm-objdump-17 13 | fi 14 | 15 | echo -e "\nInstruction counts for ${file}:\n" 16 | 17 | total=0 18 | while read line; do 19 | name=$(echo $line | awk '{ print $2 }') 20 | size="0x$(echo $line | awk '{ print $3 }')" 21 | size=$((size / 8)) # ebpf has 64-bit fixed length instructions 22 | echo "$name has $size instructions" 23 | total=$((total + size)) 24 | done < <($OBJDUMP_CMD --section-headers "${file}" | grep TEXT) 25 | 26 | echo -e "\nTotal instructions: ${total}\n" 27 | -------------------------------------------------------------------------------- /support/ebpf/sched_monitor.ebpf.c: -------------------------------------------------------------------------------- 1 | // This file contains the code and map definitions for the tracepoint on the scheduler to 2 | // report the stopping a process. 3 | 4 | #include "bpfdefs.h" 5 | #include "tracemgmt.h" 6 | 7 | #include "types.h" 8 | 9 | // See /sys/kernel/debug/tracing/events/sched/sched_process_free/format 10 | // for struct layout. 11 | struct sched_process_free_ctx { 12 | unsigned char skip[24]; 13 | pid_t pid; 14 | int prio; 15 | }; 16 | 17 | // tracepoint__sched_process_free is a tracepoint attached to the scheduler that frees processes. 18 | // Every time a processes exits this hook is triggered. 19 | SEC("tracepoint/sched/sched_process_free") 20 | int tracepoint__sched_process_free(struct sched_process_free_ctx *ctx) 21 | { 22 | u32 pid = ctx->pid; 23 | 24 | if (!bpf_map_lookup_elem(&reported_pids, &pid) && !pid_information_exists(ctx, pid)) { 25 | // Only report PIDs that we explicitly track. This avoids sending kernel worker PIDs 26 | // to userspace. 27 | goto exit; 28 | } 29 | 30 | if (report_pid(ctx, (u64)pid << 32 | pid, RATELIMIT_ACTION_RESET)) { 31 | increment_metric(metricID_NumProcExit); 32 | } 33 | exit: 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /support/ebpf/tracer.ebpf.release.amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/support/ebpf/tracer.ebpf.release.amd64 -------------------------------------------------------------------------------- /support/ebpf/tracer.ebpf.release.arm64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/support/ebpf/tracer.ebpf.release.arm64 -------------------------------------------------------------------------------- /support/ebpf/v8_tracer.h: -------------------------------------------------------------------------------- 1 | // This file contains definitions for the V8 tracer 2 | 3 | // V8 constants for the tags. Hard coded to optimize code size and speed. 4 | // They are unlikely to change, and likely require larger modifications on change. 5 | 6 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#52 7 | #define SmiTag 0x0 8 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#54 9 | #define SmiTagMask 0x1 10 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#91 11 | #define SmiTagShift 1 12 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#98 13 | #define SmiValueShift 32 14 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#39 15 | #define HeapObjectTag 0x1 16 | // https://chromium.googlesource.com/v8/v8.git/+/refs/heads/9.2.230/include/v8-internal.h#42 17 | #define HeapObjectTagMask 0x3 18 | 19 | // The Trace 'file' field is split to object pointer (aligned to 8 bytes), 20 | // and the zero bits due to alignment are re-used as the following flags. 21 | #define V8_FILE_TYPE_MARKER 0x0 22 | #define V8_FILE_TYPE_BYTECODE 0x1 23 | #define V8_FILE_TYPE_NATIVE_SFI 0x2 24 | #define V8_FILE_TYPE_NATIVE_CODE 0x3 25 | #define V8_FILE_TYPE_NATIVE_JSFUNC 0x4 26 | #define V8_FILE_TYPE_MASK 0x7 27 | 28 | // The Trace 'line' field is split to two 32-bit fields: cookie and PC-delta 29 | #define V8_LINE_COOKIE_SHIFT 32 30 | #define V8_LINE_COOKIE_MASK 0xffffffff00000000 31 | #define V8_LINE_DELTA_MASK 0x00000000ffffffff 32 | -------------------------------------------------------------------------------- /support/generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | # Put license header at the top of the file 6 | cat <types_gen.go 7 | // Copyright The OpenTelemetry Authors 8 | // SPDX-License-Identifier: Apache-2.0 9 | 10 | EOF 11 | 12 | # Generate Go definitions from C 13 | go tool cgo -godefs types_def.go >> types_gen.go 14 | 15 | # Properly format the generated code 16 | go fmt . 17 | 18 | # Set correct package path 19 | sed -i 's/^package support$/package support \/\/ import "go.opentelemetry.io\/ebpf-profiler\/support"/' types_gen.go 20 | 21 | if ! diff types_gen.go types.go; then 22 | echo "Auto generated and existing code differ, please review and update support/types.go" 23 | exit 1 24 | fi 25 | 26 | # Clean up temporary files 27 | rm -rf _obj/ types_gen.go 28 | -------------------------------------------------------------------------------- /support/helper.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // support maps the definitions from headers in the C world into a nice go way 5 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 6 | 7 | import "fmt" 8 | 9 | // EncodeBiasAndUnwindProgram encodes a bias_and_unwind_program value (for C.PIDPageMappingInfo) 10 | // from a bias and unwind program values. 11 | // This currently assumes a non-negative bias: this encoding may have to be changed if bias can be 12 | // negative. 13 | func EncodeBiasAndUnwindProgram(bias uint64, 14 | unwindProgram uint8) (uint64, error) { 15 | if (bias >> 56) > 0 { 16 | return 0, fmt.Errorf("unsupported bias value (too large): 0x%x", bias) 17 | } 18 | return bias | (uint64(unwindProgram) << 56), nil 19 | } 20 | 21 | // DecodeBiasAndUnwindProgram decodes the contents of the `bias_and_unwind_program` field in 22 | // C.PIDPageMappingInfo and returns the corresponding bias and unwind program. 23 | func DecodeBiasAndUnwindProgram(biasAndUnwindProgram uint64) (bias uint64, unwindProgram uint8) { 24 | bias = biasAndUnwindProgram & 0x00FFFFFFFFFFFFFF 25 | unwindProgram = uint8(biasAndUnwindProgram >> 56) 26 | return bias, unwindProgram 27 | } 28 | -------------------------------------------------------------------------------- /support/support.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 5 | 6 | import ( 7 | "bytes" 8 | 9 | cebpf "github.com/cilium/ebpf" 10 | log "github.com/sirupsen/logrus" 11 | ) 12 | 13 | // LoadCollectionSpec is a wrapper around ebpf.LoadCollectionSpecFromReader and loads the eBPF 14 | // Spec from the embedded file. 15 | // We expect tracerData to hold all possible eBPF maps and programs. 16 | func LoadCollectionSpec(debugTracer bool) (*cebpf.CollectionSpec, error) { 17 | if debugTracer { 18 | if len(debugTracerData) > 0 { 19 | log.Warnf("Using debug eBPF tracers") 20 | return cebpf.LoadCollectionSpecFromReader(bytes.NewReader(debugTracerData)) 21 | } 22 | log.Warnf("Debug eBPF tracers not found, using release tracers instead") 23 | } 24 | return cebpf.LoadCollectionSpecFromReader(bytes.NewReader(tracerData)) 25 | } 26 | -------------------------------------------------------------------------------- /support/support_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | import ( 9 | _ "embed" 10 | ) 11 | 12 | //go:embed ebpf/tracer.ebpf.release.amd64 13 | var tracerData []byte 14 | -------------------------------------------------------------------------------- /support/support_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | import ( 9 | _ "embed" 10 | ) 11 | 12 | //go:embed ebpf/tracer.ebpf.release.arm64 13 | var tracerData []byte 14 | -------------------------------------------------------------------------------- /support/support_others.go: -------------------------------------------------------------------------------- 1 | //go:build !arm64 && !amd64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package support // import "go.opentelemetry.io/ebpf-profiler/support" 7 | 8 | // support_dummy.go satisfies build requirements where the eBPF tracers file does 9 | // not exist. 10 | 11 | var tracerData []byte 12 | -------------------------------------------------------------------------------- /support/support_test.go: -------------------------------------------------------------------------------- 1 | package support 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestSizeOfCGoStruct(t *testing.T) { 11 | tests := []struct { 12 | // Name of Go wrapper struct 13 | name string 14 | input uintptr 15 | want uintptr 16 | }{ 17 | {name: "ApmIntProcInfo", input: unsafe.Sizeof(ApmIntProcInfo{}), 18 | want: sizeof_ApmIntProcInfo}, 19 | {name: "DotnetProcInfo", input: unsafe.Sizeof(DotnetProcInfo{}), 20 | want: sizeof_DotnetProcInfo}, 21 | {name: "PHPProcInfo", input: unsafe.Sizeof(PHPProcInfo{}), 22 | want: sizeof_PHPProcInfo}, 23 | {name: "RubyProcInfo", input: unsafe.Sizeof(RubyProcInfo{}), 24 | want: sizeof_RubyProcInfo}, 25 | } 26 | for _, tt := range tests { 27 | t.Run(tt.name, func(t *testing.T) { 28 | require.Equalf(t, tt.want, tt.input, 29 | "unsafe.Sizeof(%v{}) = %v, want %v", tt.name, tt.input, tt.want) 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /target/aarch64-unknown-linux-musl/release/libsymblib_capi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/target/aarch64-unknown-linux-musl/release/libsymblib_capi.a -------------------------------------------------------------------------------- /target/x86_64-unknown-linux-musl/release/libsymblib_capi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/target/x86_64-unknown-linux-musl/release/libsymblib_capi.a -------------------------------------------------------------------------------- /times/ktime.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package times // import "go.opentelemetry.io/ebpf-profiler/times" 5 | 6 | import ( 7 | "time" 8 | _ "unsafe" // required to use //go:linkname for runtime.nanotime 9 | ) 10 | 11 | // KTime stores a time value, retrieved from a monotonic clock, in nanoseconds 12 | type KTime int64 13 | 14 | // GetKTime gets the current time in same nanosecond format as bpf_ktime_get_ns() eBPF call 15 | // This relies runtime.nanotime to use CLOCK_MONOTONIC. If this changes, this needs to 16 | // be adjusted accordingly. Using this internal is superior in performance, as it is able 17 | // to use the vDSO to query the time without syscall. 18 | // 19 | //go:noescape 20 | //go:linkname GetKTime runtime.nanotime 21 | func GetKTime() KTime 22 | 23 | // Time converts the kernel timestamp into a Go time object. 24 | func (t KTime) Time() time.Time { 25 | return time.Unix(0, t.UnixNano()) 26 | } 27 | 28 | // UnixNano converts the kernel timestamp to nanoseconds since the epoch. 29 | func (t KTime) UnixNano() int64 { 30 | return int64(t) + bootTimeUnixNano.Load() 31 | } 32 | -------------------------------------------------------------------------------- /tools/coredump/.gitignore: -------------------------------------------------------------------------------- 1 | /coredump 2 | /coredump.test 3 | /testsources/java/*.class 4 | /modulecache 5 | /gdb-sysroot 6 | 7 | -------------------------------------------------------------------------------- /tools/coredump/coredump_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "context" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func TestCoreDumps(t *testing.T) { 14 | cases, err := findTestCases(true) 15 | require.NoError(t, err) 16 | require.NotEmpty(t, cases) 17 | 18 | store, err := initModuleStore() 19 | require.NoError(t, err) 20 | 21 | for _, filename := range cases { 22 | filename := filename 23 | t.Run(filename, func(t *testing.T) { 24 | testCase, err := readTestCase(filename) 25 | require.NoError(t, err) 26 | 27 | ctx := context.Background() 28 | 29 | core, err := OpenStoreCoredump(store, testCase.CoredumpRef, testCase.Modules) 30 | require.NoError(t, err) 31 | defer core.Close() 32 | 33 | data, err := ExtractTraces(ctx, core, false, nil) 34 | 35 | require.NoError(t, err) 36 | require.Equal(t, testCase.Threads, data) 37 | }) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/coredump/exportmodule.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | "flag" 10 | "fmt" 11 | 12 | "github.com/peterbourgon/ff/v3/ffcli" 13 | 14 | "go.opentelemetry.io/ebpf-profiler/tools/coredump/modulestore" 15 | ) 16 | 17 | type exportModuleCmd struct { 18 | store *modulestore.Store 19 | 20 | // User-specified command line arguments. 21 | id string 22 | out string 23 | } 24 | 25 | func newExportModuleCmd(store *modulestore.Store) *ffcli.Command { 26 | cmd := exportModuleCmd{store: store} 27 | set := flag.NewFlagSet("export-module", flag.ExitOnError) 28 | set.StringVar(&cmd.id, "id", "", "ID of the module to extract [required]") 29 | set.StringVar(&cmd.out, "out", "", "Output path to write module to [required]") 30 | 31 | return &ffcli.Command{ 32 | Name: "export-module", 33 | ShortUsage: "export-module [flags]", 34 | ShortHelp: "Export a module from the module store to a local path", 35 | FlagSet: set, 36 | Exec: cmd.exec, 37 | } 38 | } 39 | 40 | func (cmd *exportModuleCmd) exec(context.Context, []string) error { 41 | if cmd.id == "" { 42 | return errors.New("missing required argument `-id`") 43 | } 44 | if cmd.out == "" { 45 | return errors.New("missing required argument `-out`") 46 | } 47 | 48 | id, err := modulestore.IDFromString(cmd.id) 49 | if err != nil { 50 | return fmt.Errorf("unable to parse module ID: %w", err) 51 | } 52 | 53 | return cmd.store.UnpackModuleToPath(id, cmd.out) 54 | } 55 | -------------------------------------------------------------------------------- /tools/coredump/modulestore/reader.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package modulestore // import "go.opentelemetry.io/ebpf-profiler/tools/coredump/modulestore" 5 | 6 | import "io" 7 | 8 | // ModuleReader allows reading a module from the module store. 9 | type ModuleReader struct { 10 | io.ReaderAt 11 | io.Closer 12 | preferredReadSize uint 13 | size uint 14 | } 15 | 16 | // PreferredReadSize returns the preferred size and alignment of reads on this reader. 17 | func (m *ModuleReader) PreferredReadSize() uint { 18 | return m.preferredReadSize 19 | } 20 | 21 | // Size returns the uncompressed size of the module. 22 | func (m *ModuleReader) Size() uint { 23 | return m.size 24 | } 25 | -------------------------------------------------------------------------------- /tools/coredump/modulestore/util.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package modulestore // import "go.opentelemetry.io/ebpf-profiler/tools/coredump/modulestore" 5 | 6 | import ( 7 | "context" 8 | "errors" 9 | "fmt" 10 | 11 | "github.com/aws/aws-sdk-go-v2/service/s3" 12 | s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" 13 | ) 14 | 15 | // getS3ObjectList gets all matching objects in an S3 bucket. 16 | func getS3ObjectList(client *s3.Client, bucket, prefix string, 17 | itemLimit int) ([]s3types.Object, error) { 18 | var objects []s3types.Object 19 | var contToken *string 20 | var batchSize int32 = s3ResultsPerPage 21 | 22 | for { 23 | resp, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{ 24 | Bucket: &bucket, 25 | Prefix: &prefix, 26 | MaxKeys: &batchSize, 27 | ContinuationToken: contToken, 28 | }) 29 | 30 | if err != nil { 31 | return nil, fmt.Errorf("s3 request failed: %w", err) 32 | } 33 | 34 | objects = append(objects, resp.Contents...) 35 | 36 | if int32(len(resp.Contents)) != batchSize { 37 | break 38 | } 39 | if len(resp.Contents) > itemLimit { 40 | return nil, errors.New("too many matching items in bucket") 41 | } 42 | 43 | contToken = resp.ContinuationToken 44 | } 45 | 46 | return objects, nil 47 | } 48 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/tools/coredump/testdata/amd64/.gitkeep -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/brokenstack.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "20e6703ba5278290b6ec913da9605927ec95a4bde97c7ec22b30b9d49ffc4e9b", 3 | "threads": [ 4 | { 5 | "lwp": 1458, 6 | "frames": [ 7 | "brokenstack+0x1148", 8 | "brokenstack+0x1156", 9 | "brokenstack+0x1176", 10 | "" 11 | ] 12 | } 13 | ], 14 | "modules": [ 15 | { 16 | "ref": "46e6661eca1c28e6fd3ab6a586994d9d9eb2dd56a233ad1d1bf6b4ca68d91707", 17 | "local-path": "/usr/lib/x86_64-linux-gnu/libc.so.6" 18 | }, 19 | { 20 | "ref": "838ed8808d15fb09e04381d36a36eb45de3622d7d1d0bb1fac6722ccab2eb80e", 21 | "local-path": "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" 22 | }, 23 | { 24 | "ref": "e1972e610166390de54af6360388c72fbc2b2c6e51faaee9f07d3800f6b3cd67", 25 | "local-path": "/home/admin/prodfiler/utils/coredump/testsources/c/brokenstack" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/glibc-signalframe.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "1ac58fb10376e3f36837381be9ace59a92f8d1d57adcf3cadf43498dd3232a6d", 3 | "threads": [ 4 | { 5 | "lwp": 7331, 6 | "frames": [ 7 | "libc.so.6+0xcf303", 8 | "libc.so.6+0xd3c52", 9 | "libc.so.6+0xd3b89", 10 | "sig+0x1182", 11 | "libc.so.6+0x3bf8f", 12 | "libc.so.6+0xcf303", 13 | "libc.so.6+0xd3c52", 14 | "libc.so.6+0xd3b89", 15 | "sig+0x11bc", 16 | "libc.so.6+0x27189", 17 | "libc.so.6+0x27244", 18 | "sig+0x1090" 19 | ] 20 | } 21 | ], 22 | "modules": [ 23 | { 24 | "ref": "6cafb43b441840662cb52a035413f968c9cbb19c84725246e0d221186bdd4fa7", 25 | "local-path": "/root/sig" 26 | }, 27 | { 28 | "ref": "436bf9e45334ab7e44fa78ab06d2578af34eac8dece2b4cb373ba4be73dac86c", 29 | "local-path": "/usr/lib/x86_64-linux-gnu/libc.so.6" 30 | }, 31 | { 32 | "ref": "fa00e11432d68470e2b429605cff856659892611eec3a0908af7e077d2295c27", 33 | "local-path": "/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/graalvm-native.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "e7fa60d8b9eddd1a29c2aeea9b21ef625fa3ad1559e37a5433958620c9841f1f", 3 | "threads": [ 4 | { 5 | "lwp": 3327417, 6 | "frames": [ 7 | "hellograal+0x8a1202", 8 | "" 9 | ] 10 | }, 11 | { 12 | "lwp": 3327418, 13 | "frames": [ 14 | "libc.so.6+0x899d9", 15 | "libc.so.6+0x8c1cf", 16 | "hellograal+0x4a8886", 17 | "" 18 | ] 19 | } 20 | ], 21 | "modules": [ 22 | { 23 | "ref": "0190b9e6ab340b56865adbe256079ca78cb85c68a8ce7a02966d5c06b3d2bf19", 24 | "local-path": "/usr/bin/hellograal" 25 | }, 26 | { 27 | "ref": "a6b00848f58baa766d64522b36809d59da74d304bb97cf3222c2cd1275cefc19", 28 | "local-path": "/usr/lib64/libc.so.6" 29 | }, 30 | { 31 | "ref": "9330290f707b9f543f3e65e455ee1465a1825e71418b1e8756e01596e7a51d93", 32 | "local-path": "/usr/lib64/libz.so.1.2.11" 33 | }, 34 | { 35 | "ref": "9da4ee579134fd34f8b8ea536a02929d2711b387229b777cae63599b24c5229f", 36 | "local-path": "/usr/lib64/ld-linux-x86-64.so.2" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/musl-signalframe.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "69d481450a189176db6d7d23bc420a5e50adff8e75c432d5f7b68547e0908c6c", 3 | "threads": [ 4 | { 5 | "lwp": 5576, 6 | "frames": [ 7 | "ld-musl-x86_64.so.1+0x54f0a", 8 | "ld-musl-x86_64.so.1+0x520ed", 9 | "ld-musl-x86_64.so.1+0x561dd", 10 | "ld-musl-x86_64.so.1+0x56546", 11 | "ld-musl-x86_64.so.1+0x5846a", 12 | "sig+0x11be", 13 | "ld-musl-x86_64.so.1+0x4662b", 14 | "ld-musl-x86_64.so.1+0x54f0a", 15 | "ld-musl-x86_64.so.1+0x520ed", 16 | "ld-musl-x86_64.so.1+0x561dd", 17 | "ld-musl-x86_64.so.1+0x56546", 18 | "ld-musl-x86_64.so.1+0x5846a", 19 | "sig+0x11f8", 20 | "ld-musl-x86_64.so.1+0x1b87f", 21 | "sig+0x1065", 22 | "" 23 | ] 24 | } 25 | ], 26 | "modules": [ 27 | { 28 | "ref": "98b7650549c4fc55448ecf25df03d4f93f3aa2ed4b23861b33b9bab09304a8fa", 29 | "local-path": "/home/tteras/work/elastic/java/sig" 30 | }, 31 | { 32 | "ref": "c3f0829a87fce28a23d4b5edea62b5513eb72fbee4a95864796e86a7737c6b9b", 33 | "local-path": "/lib/ld-musl-x86_64.so.1" 34 | }, 35 | { 36 | "ref": "c10979df29fdec45399700b27b9fa4615cbffa3523f486c80f471efa6a37170a", 37 | "local-path": "/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/openssl-gcm.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "8cda7773f5eb71c6a4039c215dc80575810061a3ddeb998eec1a70a43538d6ba", 3 | "threads": [ 4 | { 5 | "lwp": 17068, 6 | "frames": [ 7 | "libcrypto.so.3+0x575c0", 8 | "libcrypto.so.3+0x22542f", 9 | "libcrypto.so.3+0x2b7ec8", 10 | "libcrypto.so.3+0x2ed50c", 11 | "libcrypto.so.3+0x2ede24", 12 | "libcrypto.so.3+0x14b6d5", 13 | "openssl+0x54967", 14 | "openssl+0x55595", 15 | "openssl+0x57d15", 16 | "openssl+0x3a5bb", 17 | "openssl+0x1c240", 18 | "ld-musl-x86_64.so.1+0x1c6d0", 19 | "openssl+0x1c2ed" 20 | ] 21 | } 22 | ], 23 | "modules": [ 24 | { 25 | "ref": "ca95248c3b9da61b945c031c8bd0a97740f27d1681141e24bd3a791606863ad0", 26 | "local-path": "/usr/lib/debug/lib/ld-musl-x86_64.so.1.debug" 27 | }, 28 | { 29 | "ref": "85ae4badf742d07f643e644d1b9f63e03b26ce7bcd9a39166af37e0ca90883d8", 30 | "local-path": "/lib/libcrypto.so.3" 31 | }, 32 | { 33 | "ref": "898a5f8b56c3c24554799885201c9c8aa1e3ed8c7b71b2cb298615d136fcbdb2", 34 | "local-path": "/lib/libssl.so.3" 35 | }, 36 | { 37 | "ref": "a5efce0d5ad293660ba30a4b4b7e059dbf61ab902e04353cfc0510e34118f375", 38 | "local-path": "/usr/bin/openssl" 39 | }, 40 | { 41 | "ref": "16c1e108145e26ee4b2c693548216428cadbcc8499b1a9993442c490f4aa3590", 42 | "local-path": "/lib/ld-musl-x86_64.so.1" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/openssl.14327.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "019365b70eb446b26375019b34c87bc0fe2cbd2f8b50b4f8de38f12b6b4670cf", 3 | "threads": [ 4 | { 5 | "lwp": 14327, 6 | "frames": [ 7 | "libcrypto.so.1.1+0x19759b", 8 | "libcrypto.so.1.1+0x19780a", 9 | "libcrypto.so.1.1+0x1351e7", 10 | "libcrypto.so.1.1+0x9fe54", 11 | "libcrypto.so.1.1+0x9f1a5", 12 | "libcrypto.so.1.1+0x9f588", 13 | "openssl+0x3b39a", 14 | "openssl+0x3c0b7", 15 | "openssl+0x44c54", 16 | "openssl+0x323f4", 17 | "ld-musl-x86_64.so.1+0x1ca02", 18 | "openssl+0x325b9" 19 | ] 20 | } 21 | ], 22 | "modules": null 23 | } 24 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl528.14.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "462c77ccad87047ed1c2dceed36af11abaa155823f03a65622a0e8a3c416c101", 3 | "threads": [ 4 | { 5 | "lwp": 14, 6 | "frames": [ 7 | "libpthread-2.28.so+0x11471", 8 | "perl+0x173cd4", 9 | "perl+0x1766f9", 10 | "perl+0x175496", 11 | "perl+0x17601c", 12 | "perl+0x14b7cd", 13 | "perl+0xe602b", 14 | "HelloWorld::print+0 in hi.pl:12", 15 | "+0 in hi.pl:19", 16 | "perl+0xe2c25", 17 | "perl+0x5e116", 18 | "perl+0x34401", 19 | "libc-2.28.so+0x2409a", 20 | "perl+0x34449" 21 | ] 22 | } 23 | ], 24 | "modules": null 25 | } 26 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl528.151.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "4f94861ca06fa1f2101387824db3bc2fc5c8af508f21e6a055d15a72fe338764", 3 | "threads": [ 4 | { 5 | "lwp": 151, 6 | "frames": [ 7 | "libc-2.28.so+0x15c751", 8 | "perl+0xfa5b8", 9 | "perl+0xe1987", 10 | "perl+0x11cc2c", 11 | "HTML::Lint::Parser::_element_push+0 in /usr/share/perl5/HTML/Lint/Parser.pm:337", 12 | "HTML::Lint::Parser::_start+0 in /usr/share/perl5/HTML/Lint/Parser.pm:142", 13 | "perl+0xe2c25", 14 | "perl+0x55f61", 15 | "Parser.so+0x6458", 16 | "Parser.so+0x78a1", 17 | "Parser.so+0x89c7", 18 | "Parser.so+0x8e46", 19 | "Parser.so+0x958a", 20 | "perl+0xec900", 21 | "HTML::Lint::parse+0 in /usr/share/perl5/HTML/Lint.pm:135", 22 | "+0 in /usr/bin/weblint:67", 23 | "perl+0xe2c25", 24 | "perl+0x5e116", 25 | "perl+0x34401", 26 | "libc-2.28.so+0x2409a", 27 | "perl+0x34449" 28 | ] 29 | } 30 | ], 31 | "modules": null 32 | } 33 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl528.206.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "3f5d5c988bf17f6ce616430a7a815bbc67bbb1bb5b98bd03e5d26988f49ae2a7", 3 | "threads": [ 4 | { 5 | "lwp": 206, 6 | "frames": [ 7 | "libc-2.28.so+0xc66f4", 8 | "libc-2.28.so+0xc6629", 9 | "perl+0x141b17", 10 | "main::fib+0 in a.pl:21", 11 | "main::fib+0 in a.pl:24", 12 | "main::fib+0 in a.pl:24", 13 | "main::fib+0 in a.pl:24", 14 | "main::fib+0 in a.pl:24", 15 | "main::fib+0 in a.pl:24", 16 | "main::fib+0 in a.pl:24", 17 | "main::fib+0 in a.pl:24", 18 | "main::fib+0 in a.pl:24", 19 | "main::fib+0 in a.pl:24", 20 | "main::fib+0 in a.pl:24", 21 | "+0 in a.pl:32", 22 | "perl+0xe2c25", 23 | "perl+0x5e116", 24 | "perl+0x34401", 25 | "libc-2.28.so+0x2409a", 26 | "perl+0x34449" 27 | ] 28 | } 29 | ], 30 | "modules": null 31 | } 32 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl534.220234.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "682732701a4de336b4e9fcfd25caaf963d918ce8b5e554afeb001e63d956bd86", 3 | "threads": [ 4 | { 5 | "lwp": 220234, 6 | "frames": [ 7 | "libperl.so.5.34.0+0x14ea24", 8 | "libperl.so.5.34.0+0x14eb69", 9 | "HelloWorld::print+0 in hi.pl:11", 10 | "+0 in hi.pl:19", 11 | "libperl.so.5.34.0+0x10071f", 12 | "libperl.so.5.34.0+0x7eafb", 13 | "perl+0x1349", 14 | "libc.so.6+0x2d55f", 15 | "libc.so.6+0x2d60b", 16 | "perl+0x1384" 17 | ] 18 | } 19 | ], 20 | "modules": null 21 | } 22 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl536-a.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "2133172239f9a1934df5159c20f137f8fb128b497662fb6c419556a4be5cc9b6", 3 | "threads": [ 4 | { 5 | "lwp": 40852, 6 | "frames": [ 7 | "libc.so.6+0xd2057", 8 | "libc.so.6+0xd6846", 9 | "libc.so.6+0xd677d", 10 | "libperl.so.5.36.0+0x173c8b", 11 | "main::fib+0 in a.pl:21", 12 | "main::fib+0 in a.pl:24", 13 | "main::fib+0 in a.pl:24", 14 | "main::fib+0 in a.pl:24", 15 | "main::fib+0 in a.pl:24", 16 | "main::fib+0 in a.pl:24", 17 | "main::fib+0 in a.pl:24", 18 | "main::fib+0 in a.pl:24", 19 | "main::fib+0 in a.pl:24", 20 | "main::fib+0 in a.pl:24", 21 | "main::fib+0 in a.pl:24", 22 | "+0 in a.pl:32", 23 | "libperl.so.5.36.0+0x11084f", 24 | "libperl.so.5.36.0+0x80fa0", 25 | "perl+0x1349", 26 | "libc.so.6+0x2750f", 27 | "libc.so.6+0x275c8", 28 | "perl+0x1384" 29 | ] 30 | } 31 | ], 32 | "modules": null 33 | } 34 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/perl536-helloWorld.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "507e21408db838770bd5bd36e3a068eb22d6a6f5bc727aeedf13f6c6a29cf002", 3 | "threads": [ 4 | { 5 | "lwp": 26718, 6 | "frames": [ 7 | "libc.so.6+0xfb0c4", 8 | "libperl.so.5.36.0+0x1a15fc", 9 | "libperl.so.5.36.0+0x1a0880", 10 | "libperl.so.5.36.0+0x19781f", 11 | "libperl.so.5.36.0+0x197fc3", 12 | "libperl.so.5.36.0+0x17d7cd", 13 | "libperl.so.5.36.0+0x113bf3", 14 | "HelloWorld::print+0 in hi.pl:12", 15 | "+0 in hi.pl:19", 16 | "libperl.so.5.36.0+0x11084f", 17 | "libperl.so.5.36.0+0x80fa0", 18 | "perl+0x1349", 19 | "libc.so.6+0x2750f", 20 | "libc.so.6+0x275c8", 21 | "perl+0x1384" 22 | ] 23 | } 24 | ], 25 | "modules": null 26 | } 27 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/php74.7893.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "9ad2317b116884d61014c03f86e01054ec95e84bafcf50f031c44ede8f6ba021", 3 | "threads": [ 4 | { 5 | "lwp": 7893, 6 | "frames": [ 7 | "php7.4+0x2e9b52", 8 | "is_prime+13 in /home/j/prime.php:16", 9 | "+33 in /home/j/prime.php:34", 10 | "php7.4+0x321863", 11 | "php7.4+0x32a09a", 12 | "php7.4+0x2a2b53", 13 | "php7.4+0x2417ef", 14 | "php7.4+0x32c147", 15 | "php7.4+0x10d870", 16 | "libc-2.31.so+0x26d09", 17 | "php7.4+0x10d9e9" 18 | ] 19 | } 20 | ], 21 | "modules": null 22 | } 23 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/php8.103871.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "565f0a1cc5634a769d422821d2ac8659dbad90892d475451b784506402ccc206", 3 | "threads": [ 4 | { 5 | "lwp": 103871, 6 | "frames": [ 7 | "libc-2.31.so+0xeef33", 8 | "php8.0+0x34f0f0", 9 | "php8.0+0x34f16a", 10 | "php8.0+0x26ce30", 11 | "php8.0+0x26cf64", 12 | "php8.0+0x2e3140", 13 | "+5 in /home/j/run_forever.php:6", 14 | "php8.0+0x32070b", 15 | "php8.0+0x32969c", 16 | "php8.0+0x2bfc34", 17 | "php8.0+0x25b5bc", 18 | "php8.0+0x34efb4", 19 | "php8.0+0x116d30", 20 | "libc-2.31.so+0x26d09", 21 | "php8.0+0x116ea9" 22 | ] 23 | } 24 | ], 25 | "modules": null 26 | } 27 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/python310.stringbench.20086.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "caf74bc49055cd6959fe96a6c14b19da025254b2351293a1b9d1b9165d78074e", 3 | "threads": [ 4 | { 5 | "lwp": 20086, 6 | "frames": [ 7 | "libpython3.10.so.1.0+0x126a16", 8 | "libpython3.10.so.1.0+0x190a07", 9 | "libpython3.10.so.1.0+0x11e986", 10 | "rpartition_test_slow_match_two_characters+2 in /home/flehner/src/github.com/python/cpython/Tools/stringbench/stringbench.py:478", 11 | "inner+1 in :3", 12 | "timeit+10 in /usr/lib64/python3.10/timeit.py:174", 13 | "best+1 in /home/flehner/src/github.com/python/cpython/Tools/stringbench/stringbench.py:1399", 14 | "main+1 in /home/flehner/src/github.com/python/cpython/Tools/stringbench/stringbench.py:1410", 15 | "+4 in /home/flehner/src/github.com/python/cpython/Tools/stringbench/stringbench.py:5" 16 | ] 17 | } 18 | ], 19 | "modules": null 20 | } 21 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/python37.26320.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "3740f861518da26014fc27f693555b7d9f2974d7f0e3c39e7eb15cca8b119b09", 3 | "threads": [ 4 | { 5 | "lwp": 26320, 6 | "frames": [ 7 | "python3.7+0x532049", 8 | "python3.7+0x5329a0", 9 | "python3.7+0x4d9964", 10 | "python3.7+0x5ccf60", 11 | "python3.7+0x5d0228", 12 | "python3.7+0x5d0548", 13 | "python3.7+0x4c27c2", 14 | "python3.7+0x54ab47", 15 | "python3.7+0x5ccd0b", 16 | "+2 in /tmp/systemtest_tmppy_1612432164662592633.py:3" 17 | ] 18 | } 19 | ], 20 | "modules": null 21 | } 22 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/ruby30.253432.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "1b496ac7c0747b896e6c5ef5720db01d900a224a529eb74d5ce0c787a7e4bcd1", 3 | "threads": [ 4 | { 5 | "lwp": 253432, 6 | "frames": [ 7 | "libruby.so.3.0.2+0x249714", 8 | "libruby.so.3.0.2+0x24aa77", 9 | "libruby.so.3.0.2+0x194bec", 10 | "libruby.so.3.0.2+0x195d12", 11 | "libruby.so.3.0.2+0x1983e1", 12 | "libruby.so.3.0.2+0x23bd74", 13 | "libruby.so.3.0.2+0x23e0d5", 14 | "libruby.so.3.0.2+0x240db6", 15 | "is_prime+0 in /home/flehner/tmp/ruby3/loop.rb:10", 16 | "sum_of_primes+0 in /home/flehner/tmp/ruby3/loop.rb:20", 17 | "
+0 in /home/flehner/tmp/ruby3/loop.rb:30", 18 | "libruby.so.3.0.2+0x2461e4", 19 | "libruby.so.3.0.2+0x24aa77", 20 | "libruby.so.3.0.2+0x1982dd", 21 | "libruby.so.3.0.2+0x23bd74", 22 | "libruby.so.3.0.2+0x23e0d5", 23 | "libruby.so.3.0.2+0x240db6", 24 | "
+0 in /home/flehner/tmp/ruby3/loop.rb:29", 25 | "libruby.so.3.0.2+0x2461e4", 26 | "libruby.so.3.0.2+0x249387", 27 | "libruby.so.3.0.2+0xb2e49", 28 | "libruby.so.3.0.2+0xb30ad", 29 | "libruby.so.3.0.2+0x23bd74", 30 | "libruby.so.3.0.2+0x23e0d5", 31 | "libruby.so.3.0.2+0x240db6", 32 | "
+0 in /home/flehner/tmp/ruby3/loop.rb:28", 33 | "libruby.so.3.0.2+0x2461e4", 34 | "libruby.so.3.0.2+0xb1c1a", 35 | "libruby.so.3.0.2+0xb54f9", 36 | "ruby-mri+0x118e", 37 | "libc.so.6+0x2d55f", 38 | "libc.so.6+0x2d60b", 39 | "ruby-mri+0x11d4" 40 | ] 41 | } 42 | ], 43 | "modules": null 44 | } 45 | -------------------------------------------------------------------------------- /tools/coredump/testdata/amd64/stackalign.4040.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "2bf8aa05076f4f1b8ce7d7cfe0174477229164f7b3e59a4ffc0c1a6bbc392926", 3 | "threads": [ 4 | { 5 | "lwp": 4040, 6 | "frames": [ 7 | "libc-2.31.so+0xcb3c3", 8 | "stackalign+0x12b0", 9 | "stackalign+0x12be", 10 | "stackalign+0x12be", 11 | "stackalign+0x12be", 12 | "stackalign+0x106a", 13 | "libc-2.31.so+0x26d09", 14 | "stackalign+0x10a9" 15 | ] 16 | } 17 | ], 18 | "modules": null 19 | } 20 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-ebpf-profiler/58646e7b44e171711366f76504ef692dfa62a3e0/tools/coredump/testdata/arm64/.gitkeep -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/brokenstack.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "970f0555ecdcb052c566a4502e0889c3af21b1b83ba69dc30c9bc21f7cd2003b", 3 | "threads": [ 4 | { 5 | "lwp": 32071, 6 | "frames": [ 7 | "brokenstack+0x768", 8 | "brokenstack+0x77f", 9 | "brokenstack+0x7a7", 10 | "" 11 | ] 12 | } 13 | ], 14 | "modules": [ 15 | { 16 | "ref": "9737f2a0aa44a493f1078879a4a5a45f8669c21c4d24b0f7666417888bbeff5b", 17 | "local-path": "/media/share/Development/prodfiler/utils/coredump/testsources/c/brokenstack" 18 | }, 19 | { 20 | "ref": "d985b3f544f1d4ff3c152004dafab112269eb9b5424723e02ff1f2b65ef39825", 21 | "local-path": "/usr/lib/aarch64-linux-gnu/libc.so.6" 22 | }, 23 | { 24 | "ref": "de247820b5edcc25519996cbefa697459ff0a64ff4d2a5a2e1b7b3c468c3da3e", 25 | "local-path": "/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/glibc-signal-arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "6a7fdbf45a7cc74b556668eea4bc54310bcc12d5b6fbd8bef87235d6c1c1e021", 3 | "threads": [ 4 | { 5 | "lwp": 17849, 6 | "frames": [ 7 | "libc.so.6+0xc090c", 8 | "libc.so.6+0xc5c5f", 9 | "libc.so.6+0xc5b0f", 10 | "sig+0x4101f7", 11 | "linux-vdso.1.so+0x803", 12 | "libc.so.6+0xc0910", 13 | "libc.so.6+0xc5c5f", 14 | "libc.so.6+0xc5b0f", 15 | "sig+0x410237", 16 | "libc.so.6+0x35a73", 17 | "libc.so.6+0x35b5b", 18 | "sig+0x4100ef" 19 | ] 20 | } 21 | ], 22 | "modules": [ 23 | { 24 | "ref": "0fdfedf4db555c77c21e4e942b747963b08f35890fe61c4562e2e1a07853e559", 25 | "local-path": "/home/ec2-user/sig" 26 | }, 27 | { 28 | "ref": "7436f95b8689a98ab322c19f96621da984d7062555107b55ac42d03303d9eaaa", 29 | "local-path": "/usr/lib64/libc.so.6" 30 | }, 31 | { 32 | "ref": "20b53776e9fc8e7263c1911b7e338119c777212ffe6028cfe3e524796e403736", 33 | "local-path": "/usr/lib/ld-linux-aarch64.so.1" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/perl-5.38-debian.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "6c3938b0a7f50a81f329046290b83d95f28924691d3530608ce6bb36d8ec1b76", 3 | "threads": [ 4 | { 5 | "lwp": 1212873, 6 | "frames": [ 7 | "perl+0x1228d0", 8 | "perl+0x13426f", 9 | "+0 in hi.pl:19", 10 | "perl+0x128563", 11 | "perl+0x6d5d7", 12 | "perl+0x44907", 13 | "libc.so.6+0x26dc3", 14 | "libc.so.6+0x26e97", 15 | "perl+0x4496f" 16 | ] 17 | } 18 | ], 19 | "modules": [ 20 | { 21 | "ref": "93e7f5b5025839d2f8044bcc3fff187da48a5bd72d009d82fcf291f9eeafec36", 22 | "local-path": "/usr/bin/perl" 23 | }, 24 | { 25 | "ref": "7c3e45de45fa8de1ddc924678f9dfa4342ae0addb23c8491b3997053dfbe2524", 26 | "local-path": "/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1" 27 | }, 28 | { 29 | "ref": "c262feb3322a8a30259ba80fd68302394aaee6a46614dad7be2dcbf4d27f4cf7", 30 | "local-path": "/usr/lib/aarch64-linux-gnu/libcrypt.so.1.1.0" 31 | }, 32 | { 33 | "ref": "6fe4505b7f395f8a104ae2e3eb1f130fc585037922d8b61607e2728c6ab3419f", 34 | "local-path": "/usr/lib/aarch64-linux-gnu/libc.so.6" 35 | }, 36 | { 37 | "ref": "d03f73f8005b96a248a2e8f4a9fb2d5b15050303cd56fed1d64e9f50db6713a7", 38 | "local-path": "/usr/lib/aarch64-linux-gnu/libm.so.6" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/php81.571415.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "98c8be16cd50150fcfba63823bcdf991dbfbb8b8577c4e722662d881170e82b6", 3 | "threads": [ 4 | { 5 | "lwp": 571415, 6 | "frames": [ 7 | "php8.1+0x1ed574", 8 | "shuffle+0 in :0", 9 | "run_forever+3 in /home/admin/php_forever.php:6", 10 | "+19 in /home/admin/php_forever.php:20", 11 | "php8.1+0x33e730", 12 | "php8.1+0x349d77", 13 | "php8.1+0x2cb883", 14 | "php8.1+0x2666fb", 15 | "php8.1+0x3bd2c3", 16 | "php8.1+0x1091bf", 17 | "libc-2.33.so+0x21613", 18 | "php8.1+0x1093f7" 19 | ] 20 | } 21 | ], 22 | "modules": null 23 | } 24 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/python37.stringbench.10656.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "0c46e3e8b635c3db2244eb7c56f56d0146f754ad4cdb8b86fc4259f2e5875f31", 3 | "threads": [ 4 | { 5 | "lwp": 10656, 6 | "frames": [ 7 | "libpython3.7m.so.1.0+0xcd0f0", 8 | "libpython3.7m.so.1.0+0x10652f", 9 | "concat_many_strings+25 in stringbench.py:669", 10 | "inner+4 in :6", 11 | "timeit+14 in /usr/lib64/python3.7/timeit.py:177", 12 | "best+8 in stringbench.py:1406", 13 | "main+38 in stringbench.py:1447", 14 | "+1477 in stringbench.py:1482" 15 | ] 16 | } 17 | ], 18 | "modules": null 19 | } 20 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/stackalign.19272.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "8e03102e5ff19676e3fdd3ad942b9d9e085c2c29e32f4c834cb0ffe1e09a537f", 3 | "threads": [ 4 | { 5 | "lwp": 19272, 6 | "frames": [ 7 | "stackalign+0x860", 8 | "stackalign+0x70f", 9 | "libc-2.33.so+0x24ad3", 10 | "stackalign+0x777" 11 | ] 12 | } 13 | ], 14 | "modules": null 15 | } 16 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/stackalign.67475.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "4533ef3d0fdf4e16f093e7aa26e14d26da3e9ba9779b4e86cf446143361f9986", 3 | "threads": [ 4 | { 5 | "lwp": 67475, 6 | "frames": [ 7 | "libc-2.33.so+0xa4b60", 8 | "stackalign+0x95f", 9 | "stackalign+0x96f", 10 | "stackalign+0x96f", 11 | "stackalign+0x96f", 12 | "stackalign+0x70f", 13 | "libc-2.33.so+0x21613", 14 | "stackalign+0x777" 15 | ] 16 | } 17 | ], 18 | "modules": [ 19 | { 20 | "ref": "b95a10cd6c5a218f195287bda176bc162091b2aeaeab7f0fae45fed8d4075c0e", 21 | "local-path": "/media/psf/devel/prodfiler/utils/coredump/testsources/c/stackalign" 22 | }, 23 | { 24 | "ref": "1159053678e9e948b064a36d9abad8592e195a4815a3ecfddd6c4c6da86fea54", 25 | "local-path": "/usr/lib/aarch64-linux-gnu/libc-2.33.so" 26 | }, 27 | { 28 | "ref": "c2bed948068b2fdbfb2daf41c7a25c4cbe69e40323bb9761061f93157941fb9c", 29 | "local-path": "/usr/lib/aarch64-linux-gnu/ld-2.33.so" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/stackalign.7265.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "3effcb31df636723dcfb07ccf2ab0dfd0ac093ff1fd1911dd67c50858e41d876", 3 | "threads": [ 4 | { 5 | "lwp": 7265, 6 | "frames": [ 7 | "libc-2.33.so+0xa8020", 8 | "stackalign+0x95f", 9 | "stackalign+0x96f", 10 | "stackalign+0x96f", 11 | "stackalign+0x96f", 12 | "stackalign+0x70f", 13 | "libc-2.33.so+0x24ad3", 14 | "stackalign+0x777" 15 | ] 16 | } 17 | ], 18 | "modules": null 19 | } 20 | -------------------------------------------------------------------------------- /tools/coredump/testdata/arm64/vdso-frame.json: -------------------------------------------------------------------------------- 1 | { 2 | "coredump-ref": "5b8fed37692abe90d442acbecf7d64852469af2d5c8d48858aadbcb0956586bd", 3 | "threads": [ 4 | { 5 | "lwp": 1016, 6 | "frames": [ 7 | "linux-vdso.1.so+0x50c", 8 | "linux-vdso.1.so+0x7df", 9 | "libc.so.6+0xbbccb", 10 | "cpuhog+0x857", 11 | "libc.so.6+0x284c3", 12 | "libc.so.6+0x28597", 13 | "cpuhog+0x72f" 14 | ] 15 | } 16 | ], 17 | "modules": [ 18 | { 19 | "ref": "e27e9ec53f7479924b46bdf8b22f0cba26f46cd0683e31b03d8d64b564baa6b5", 20 | "local-path": "/home/ubuntu/cpuhog" 21 | }, 22 | { 23 | "ref": "0740600899deec69af5e1a2110a9007ffd6af83dfe17b25d87fd3a48ae335dd0", 24 | "local-path": "/usr/lib/aarch64-linux-gnu/libc.so.6" 25 | }, 26 | { 27 | "ref": "7e1f26ba5a3b84dbf6fbfac1e318a7b0320eb1214f0e409905f207f1c9a2616b", 28 | "local-path": "/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /tools/coredump/testsources/c/brokenstack.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Example application that intentionally breaks its stack. 5 | // 6 | // cc -O2 -g -o brokenstack brokenstack.c 7 | 8 | #include 9 | 10 | #define FORCE_FRAME \ 11 | __attribute__((noinline)) \ 12 | __attribute__((optimize("no-omit-frame-pointer"))) \ 13 | __attribute__((optimize("no-optimize-sibling-calls"))) 14 | 15 | static volatile int cond = 1; 16 | 17 | FORCE_FRAME void a() { 18 | while(cond); 19 | } 20 | 21 | FORCE_FRAME void b() { 22 | a(); 23 | } 24 | 25 | FORCE_FRAME void c() { 26 | uint64_t* frame = __builtin_frame_address(0); 27 | frame[0] = 0x42; 28 | frame[1] = 0x42; 29 | b(); 30 | } 31 | 32 | int main() { 33 | c(); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /tools/coredump/testsources/c/cpuhog.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) 4 | { 5 | struct timespec res; 6 | 7 | while (1) { 8 | clock_gettime(CLOCK_MONOTONIC, &res); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/coredump/testsources/c/sig.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | unsigned long special_symbol = 0xdeadbeef; 9 | 10 | void sig_handler(int signo) 11 | { 12 | if (signo == SIGINT) 13 | printf("received SIGINT\n"); 14 | sleep(10); 15 | } 16 | 17 | int main(void) 18 | { 19 | if (signal(SIGINT, sig_handler) == SIG_ERR) 20 | printf("\ncan't catch SIGINT\n"); 21 | // A long long wait so that we can easily issue a signal to this process 22 | while(1) 23 | sleep(1); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tools/coredump/testsources/c/stackalign.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // gcc -O3 -fomit-frame-pointer -mavx -ftree-vectorize stackalign.c -o stackalign 5 | 6 | #include 7 | #include 8 | 9 | int calc(int r) 10 | { 11 | const int N = 2000; //Array Size 12 | const int noTests = 10000; //Number of tests 13 | float a[N],b[N],c[N],result[N]; 14 | 15 | for (int i = 0; i < N; ++i) { 16 | a[i] = ((float)i)+ 0.1335f; 17 | b[i] = 1.50f*((float)i)+ 0.9383f; 18 | c[i] = 0.33f*((float)i)+ 0.1172f; 19 | } 20 | 21 | for (int i = 0; i < noTests; ++i) 22 | for (int j = 0; j < N; ++j) 23 | result[j] = a[j]+b[j]-c[j]+3*(float)i; 24 | 25 | while (r == 3) pause(); 26 | 27 | calc(r+1); 28 | 29 | fprintf(stderr, "calc(%d) done\n", r); 30 | } 31 | 32 | int main(void) 33 | { 34 | calc(0); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /tools/coredump/testsources/dotnet/helloworld/Program.cs: -------------------------------------------------------------------------------- 1 | 2 | class foo { 3 | public void bar() { 4 | Console.WriteLine("Hello, World!"); 5 | } 6 | }; 7 | 8 | class main { 9 | public static void Main() { 10 | foo bar = new foo(); 11 | while (true) { 12 | bar.bar(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tools/coredump/testsources/dotnet/helloworld/helloworld.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0;net7.0;net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tools/coredump/testsources/go/hello.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | //go:noinline 9 | func leaf() {} 10 | 11 | //go:noinline 12 | func hello() { 13 | fmt.Println("hello world!") 14 | hello1() 15 | } 16 | 17 | //go:noinline 18 | func hello1() { 19 | hello2() 20 | fmt.Println("hello world!") 21 | } 22 | 23 | //go:noinline 24 | func hello2() { 25 | fmt.Println("hello world!") 26 | x := make([]uint32, 3345) 27 | hello3(x) 28 | } 29 | 30 | //go:noinline 31 | func hello3(x []uint32) { 32 | hello4() 33 | fmt.Printf("hello world! %x", x[2234]) 34 | } 35 | 36 | //go:noinline 37 | func hello4() { 38 | hello5() 39 | fmt.Println("hello world!") 40 | } 41 | 42 | //go:noinline 43 | func hello5() { 44 | fmt.Println("hello world!") 45 | leaf() 46 | } 47 | 48 | func main() { 49 | hello() 50 | } 51 | -------------------------------------------------------------------------------- /tools/coredump/testsources/graalvm/.gitignore: -------------------------------------------------------------------------------- 1 | co 2 | hellograal 3 | hellograal.* 4 | -------------------------------------------------------------------------------- /tools/coredump/testsources/graalvm/HelloGraal.java: -------------------------------------------------------------------------------- 1 | package co.elastic.profiling; 2 | 3 | import java.security.SecureRandom; 4 | 5 | public class HelloGraal { 6 | 7 | public static void main(String[] args) { 8 | SecureRandom rand = new SecureRandom(); 9 | long maxCounter = 10000000l; 10 | 11 | for (long i = 0; i < maxCounter; i++) { 12 | // trigger page fault 13 | byte[] randomBytes = new byte[4444]; 14 | rand.nextBytes(randomBytes); 15 | 16 | if (i > 0 && (maxCounter - i) % 10000 == 0) { 17 | System.out.printf("Progress reading from rand: %d out of %d %n", i , maxCounter); 18 | } 19 | } 20 | 21 | System.out.println("Done!"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools/coredump/testsources/graalvm/Makefile: -------------------------------------------------------------------------------- 1 | build-java: 2 | @javac -d . HelloGraal.java 3 | 4 | build-executable: build-java 5 | @native-image -cp . co.elastic.profiling.HelloGraal hellograal 6 | 7 | clean: 8 | @rm -rf hellograal co 9 | -------------------------------------------------------------------------------- /tools/coredump/testsources/graalvm/README.md: -------------------------------------------------------------------------------- 1 | ## Testing GraalVM native images 2 | 3 | ### Pre-requisites 4 | 5 | 1. [download and install GraalVM for Linux](https://www.graalvm.org/22.3/docs/getting-started/linux/) 6 | 2. setup GraalVM as default Java runtime 7 | 3. install the `native-image` compiler, see more details in the 8 | [docs](https://www.graalvm.org/22.3/reference-manual/native-image/#install-native-image) 9 | 10 | ### Run the experiment 11 | 12 | - Build a native image executable from the code in HelloGraal.java 13 | ```bash 14 | make build-executable 15 | ``` 16 | - Start the host-agent 17 | - Run the `hellograal` binary 18 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/Deopt.java: -------------------------------------------------------------------------------- 1 | // Works together with DeoptFoo, and triggers deoptimized frames to be seen on the stack 2 | 3 | class Deopt { 4 | public int foo; 5 | 6 | public void Bar() { 7 | foo = foo * 123; 8 | } 9 | 10 | public void Handle(int x) { 11 | for (int i = 0; i < 1000000000; i++) { 12 | Bar(); 13 | } 14 | if (x < 10) { 15 | Handle(x + 1); 16 | } else { 17 | try { 18 | ClassLoader.getSystemClassLoader().loadClass("DeoptFoo"); 19 | while (true) { 20 | System.out.print("foo\n"); 21 | } 22 | } catch (Exception e) { 23 | } 24 | } 25 | } 26 | 27 | public static void main( String []args ) throws InterruptedException { 28 | Deopt foo = new Deopt(); 29 | foo.foo = 2; 30 | while (true) { 31 | foo.Handle(1); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/DeoptFoo.java: -------------------------------------------------------------------------------- 1 | class DeoptFoo extends Deopt { 2 | public void Bar() { 3 | foo = foo * 321; 4 | } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/HelloWorld.java: -------------------------------------------------------------------------------- 1 | class HelloWorld { 2 | public static void main( String []args ) throws InterruptedException { 3 | while (true) { 4 | System.out.println( "Hello World!" ); 5 | //Thread.sleep(10); 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/Lambda1.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Collections; 3 | import java.util.Comparator; 4 | import java.lang.Thread; 5 | 6 | public class Lambda1 { 7 | public static Comparator comparator1() { 8 | return (d1, d2) -> { 9 | try { 10 | Thread.sleep(10000); // generate core from this location 11 | } catch (Exception e) { 12 | } 13 | return d1.compareTo(d2); 14 | }; 15 | } 16 | 17 | public static void main(String[] args) { 18 | ArrayList list = new ArrayList<>(); 19 | list.add(1.9); 20 | list.add(1.2); 21 | Collections.sort(list, comparator1()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/Prof1.java: -------------------------------------------------------------------------------- 1 | 2 | public class Prof1 { 3 | 4 | public static void main(String[] args) { 5 | StringBuilder sb = new StringBuilder(); 6 | for (int i = 0; i < 1000000; i++) { 7 | sb.append("ab"); 8 | sb.delete(0, 1); 9 | } 10 | System.out.println(sb.length()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/Prof2.java: -------------------------------------------------------------------------------- 1 | // Triggers "vtable chunks" frames 2 | 3 | import java.util.function.Supplier; 4 | 5 | public class Prof2 { 6 | 7 | public static void main(String[] args) { 8 | Supplier[] suppliers = { 9 | () -> 0, 10 | () -> 1.0, 11 | () -> "abc", 12 | () -> true 13 | }; 14 | 15 | for (int i = 0; i >= 0; i++) { 16 | suppliers[i % suppliers.length].get(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/PrologueEpilogue.java: -------------------------------------------------------------------------------- 1 | /* 2 | gdb -x ./javagdbinit --args java -Xcomp \ 3 | -XX:+UnlockDiagnosticVMOptions \ 4 | "-XX:CompileCommand=dontinline *PrologueEpilogue.*" \ 5 | "-XX:CompileCommand=BreakAtExecute *PrologueEpilogue.*" \ 6 | "-XX:CompileCommand=compileonly *PrologueEpilogue.*" \ 7 | -XX:+PrintOptoAssembly -XX:+PrintAssembly -XX:-UseOnStackReplacement \ 8 | -XX:-TieredCompilation PrologueEpilogue 9 | */ 10 | 11 | class PrologueEpilogue { 12 | static int a() { 13 | return b(); 14 | } 15 | 16 | static int b() { 17 | return c(); 18 | } 19 | 20 | static int c() { 21 | return 42; 22 | } 23 | 24 | public static void main(String [] argv) { 25 | int ctr = 123; 26 | for (long i = 0; i < 100; ++i) { 27 | ctr += a(); 28 | } 29 | System.out.println(ctr); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/ShaShenanigans.java: -------------------------------------------------------------------------------- 1 | // Reduced variant of Jonas Kunz' CPU burner application. Pressures SHA256 2 | // which is implemented via StubRoutines. 3 | 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.Random; 7 | 8 | public class ShaShenanigans { 9 | public static volatile Object sink; 10 | 11 | public static void main(String[] args) { 12 | while (true) { 13 | shaShenanigans(); 14 | } 15 | } 16 | 17 | public static void shaShenanigans() { 18 | long start = System.nanoTime(); 19 | while ((System.nanoTime() - start) < 100_000_000L) { 20 | sink = hashRandomStuff(); 21 | } 22 | } 23 | 24 | private static byte[] hashRandomStuff() { 25 | try { 26 | MessageDigest digest = MessageDigest.getInstance("SHA-256"); 27 | Random rnd = new Random(); 28 | byte[] buffer = new byte[1024]; 29 | rnd.nextBytes(buffer); 30 | for(int i=0; i<5000; i++) { 31 | digest.update(buffer); 32 | } 33 | return digest.digest(); 34 | } catch (NoSuchAlgorithmException e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/VdsoPressure.java: -------------------------------------------------------------------------------- 1 | import java.lang.System; 2 | 3 | class VdsoPressure { 4 | public static void main(String [] argv) { 5 | long ctr = 0; 6 | for (long i = 0; i < 10_000_000_000L; ++i) { 7 | ctr += System.nanoTime(); 8 | } 9 | System.out.println(ctr); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tools/coredump/testsources/java/javagdbinit: -------------------------------------------------------------------------------- 1 | handle SIGILL nostop 2 | handle SIGSEGV nostop 3 | set pagination off 4 | -------------------------------------------------------------------------------- /tools/coredump/testsources/node/async.js: -------------------------------------------------------------------------------- 1 | const meetCustomer = (id) => { 2 |   return new Promise((resolve, reject) => { 3 |     setTimeout(() => { 4 |       console.log(`Waiter approached customer at table #${id}...`); 5 |       resolve({ customerId: id }); 6 |     }, id); 7 |   }); 8 | } 9 | const getOrder = (id) => { 10 |   return new Promise((resolve, reject) => { 11 |     setTimeout(() => { 12 |       console.log(`Order Received for customer at table #${id}...`); 13 |       resolve({ customerId: id, customerOrder: "Pizza" }); 14 |     }, 1); 15 |   }); 16 | } 17 | const notifyWaiter = (id) => { 18 |   return new Promise((resolve, reject) => { 19 |     setTimeout(() => { 20 |       console.log(`Order for customer at table #${id} processed....`); 21 |       resolve({ customerId: id, customerOrder: "Pizza" }); 22 |       // reject(new Error("Error occurred with waiter")); 23 |     }, 1); 24 |   }); 25 | } 26 | const serveCustomer = (id) => { 27 |   return new Promise((resolve, reject) => { 28 | for (let foo=0; foo <1000; foo++) { 29 | console.trace("I am here"); 30 | } 31 |     setTimeout(() => { 32 |       console.log(`Customer with order number #${id} served...`); 33 |       resolve({ customerId: id, customerOrder: "Pizza" }); 34 |     }, id); 35 |   }); 36 | } 37 | 38 | // Async- await approach 39 | const runRestaurant = async (customerId) => { 40 |   const customer = await meetCustomer(customerId) 41 |   const order = await getOrder(customer.customerId) 42 |   await notifyWaiter(order.customerId) 43 |   await serveCustomer(order.customerId) 44 | console.log(`Order of customer fulfilled...`) 45 | } 46 | 47 | for (let i = 0; i < 1000; i++) { 48 |   console.log(`Order Received for customer at table #${i}...`); 49 | runRestaurant(i); 50 | } 51 | -------------------------------------------------------------------------------- /tools/coredump/testsources/node/hello.js: -------------------------------------------------------------------------------- 1 | function bar(a, s) { 2 | a(s) 3 | //ads 4 | } 5 | 6 | function foo() { 7 | bar(a, "Hello world!") 8 | } 9 | 10 | console.trace("I am here"); 11 | a = console.log 12 | for (i = 0; i < 10000000; i++) { 13 | foo() 14 | } 15 | 16 | -------------------------------------------------------------------------------- /tools/coredump/testsources/node/hello2.js: -------------------------------------------------------------------------------- 1 | function bar(a, s) { 2 | a(s) 3 | //ads 4 | } 5 | 6 | function foo() { 7 | bar(a, "Hello world!") 8 | } 9 | 10 | function doit() { 11 | for (i = 0; i < 1000; i++) { 12 | foo() 13 | } 14 | } 15 | 16 | console.trace("I am here"); 17 | a = console.log 18 | for (j = 0; j < 1000; j++) { 19 | doit() 20 | } 21 | 22 | -------------------------------------------------------------------------------- /tools/coredump/testsources/node/inlining.js: -------------------------------------------------------------------------------- 1 | 2 | function add(a, b) { 3 | console.trace("here") 4 | return a + b 5 | } 6 | 7 | function add3(a, b, c) { 8 | return add(a, add(b, c)) 9 | } 10 | 11 | function test(a, b, c, d) { 12 | return add3(a, b, c) == d 13 | } 14 | 15 | function submain() { 16 | for (var i = 0; i < 1000; i++) { 17 | test(i, 2*i, 3*i, 100) 18 | } 19 | } 20 | 21 | function main() { 22 | for (var i = 0; i < 1000; i++) { 23 | submain() 24 | } 25 | } 26 | 27 | main() 28 | -------------------------------------------------------------------------------- /tools/coredump/testsources/node/test.js: -------------------------------------------------------------------------------- 1 | 2 | function add(a, b) { 3 | console.trace("here") 4 | return a + b 5 | } 6 | 7 | function add3(a, b, c) { 8 | return add(a, add(b, c)) 9 | } 10 | 11 | function test(a, b, c, d) { 12 | return add3(a, b, c) == d 13 | } 14 | 15 | function submain() { 16 | for (var i = 0; i < 1000; i++) { 17 | test(i, 2*i, 3*i, 100) 18 | } 19 | } 20 | 21 | function main() { 22 | for (var i = 0; i < 1000; i++) { 23 | submain() 24 | } 25 | } 26 | 27 | main() 28 | -------------------------------------------------------------------------------- /tools/coredump/testsources/perl/a.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Perl Program to calculate Fibonancci 4 | sub fib 5 | { 6 | 7 | # Retrieving the first argument 8 | # passed with function calling 9 | my $x = $_[0]; 10 | 11 | # checking if that value is 0 or 1 12 | if ($x == 0 || $x == 1) 13 | { 14 | return 1; 15 | } 16 | 17 | # Recursively calling function with the next value 18 | # which is one less than current one 19 | else 20 | { 21 | if ($x == 20) { 22 | sleep 100; 23 | } 24 | return $x + fib($x - 1); 25 | } 26 | } 27 | 28 | # Driver Code 29 | $a = 30; 30 | 31 | # Function call and printing result after return 32 | print "Fibonancci of a number $a is ", fib($a), "\n"; 33 | -------------------------------------------------------------------------------- /tools/coredump/testsources/perl/hi.pl: -------------------------------------------------------------------------------- 1 | package HelloWorld; 2 | sub new 3 | { 4 | my $class = shift; 5 | my $self = { }; 6 | bless $self, $class; 7 | return $self; 8 | } 9 | sub print 10 | { 11 | eval { 12 | print "Hello World!\n"; 13 | } 14 | } 15 | 16 | package main; 17 | $hw = HelloWorld->new(); 18 | while (1) { 19 | $hw->print(); 20 | } 21 | -------------------------------------------------------------------------------- /tools/coredump/testsources/php/php_forever.php: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /tools/coredump/testsources/php/prime.php: -------------------------------------------------------------------------------- 1 | '.$i.', '; 37 | } 38 | } 39 | } 40 | 41 | ?> 42 | -------------------------------------------------------------------------------- /tools/coredump/testsources/python/expat.py: -------------------------------------------------------------------------------- 1 | import xml.parsers.expat 2 | 3 | def test(): 4 | while True: 5 | pass 6 | 7 | # 3 handler functions 8 | def start_element(name, attrs): 9 | print('Start element:', name, attrs) 10 | test() 11 | def end_element(name): 12 | print('End element:', name) 13 | def char_data(data): 14 | print('Character data:', repr(data)) 15 | 16 | def main(): 17 | p = xml.parsers.expat.ParserCreate() 18 | 19 | p.StartElementHandler = start_element 20 | p.EndElementHandler = end_element 21 | p.CharacterDataHandler = char_data 22 | 23 | p.Parse(""" 24 | Text goes here 25 | More text 26 | """, 1) 27 | 28 | main() 29 | -------------------------------------------------------------------------------- /tools/coredump/testsources/python/fib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | def recur_fibo(n): 4 | if n <= 1: 5 | return n 6 | else: 7 | return(recur_fibo(n-1) + recur_fibo(n-2)) 8 | 9 | while True: 10 | print(recur_fibo(42)) 11 | -------------------------------------------------------------------------------- /tools/coredump/testsources/ruby/loop.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | def is_prime(n) 4 | if n < 2 5 | return false 6 | elsif n == 2 7 | return true 8 | end 9 | 10 | ((2..(Math.sqrt(n)))).each do |i| 11 | return false if n % i == 0 12 | end 13 | return true 14 | end 15 | 16 | def sum_of_primes(n) 17 | sum_of_primes = 0 18 | x = 2 19 | while x < n 20 | if is_prime(x) 21 | sum_of_primes += x 22 | end 23 | x += 1 24 | end 25 | return sum_of_primes 26 | end 27 | 28 | loop do 29 | for i in 0..1000000 do 30 | puts i, sum_of_primes(i) 31 | end 32 | end 33 | 34 | -------------------------------------------------------------------------------- /tools/errors-codegen/bpf.h.template: -------------------------------------------------------------------------------- 1 | /* WARNING: this file is auto-generated, DO NOT CHANGE MANUALLY */ 2 | 3 | #ifndef OPTI_ERRORS_H 4 | #define OPTI_ERRORS_H 5 | 6 | typedef enum ErrorCode { 7 | {{- range $i, $el := .Errors -}} 8 | {{if $i}}{{printf ",\n"}}{{end}} 9 | // {{if .Obsolete}}Deprecated: {{end}}{{.Description}} 10 | {{enumident .Name}} = {{.ID}} 11 | {{- end}} 12 | } ErrorCode; 13 | 14 | #endif // OPTI_ERRORS_H 15 | -------------------------------------------------------------------------------- /tools/fake-apm-agent/.gitignore: -------------------------------------------------------------------------------- 1 | /fake-apm-agent 2 | /elastic-jvmti-linux-*.so 3 | 4 | -------------------------------------------------------------------------------- /tools/fake-apm-agent/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean all 2 | 3 | CC ?= cc 4 | 5 | ARCH=$(shell uname -m) 6 | LIB_NAME=elastic-jvmti-linux-$(ARCH).so 7 | 8 | ifeq ($(ARCH),aarch64) 9 | TLS_DIALECT?=desc 10 | else 11 | TLS_DIALECT?=gnu2 12 | endif 13 | 14 | all: fake-apm-agent $(LIB_NAME) 15 | 16 | $(LIB_NAME): fake-apm-agent-lib.c 17 | $(CC) $< -g -shared -fPIC -mtls-dialect=$(TLS_DIALECT) -ftls-model=global-dynamic -o $@ 18 | 19 | fake-apm-agent: fake-apm-agent.c 20 | $(CC) $< -g -DLIB_NAME='"$(LIB_NAME)"' -o $@ 21 | 22 | clean: 23 | rm elastic-jvmti-linux-$(ARCH).so 24 | rm fake-apm-agent 25 | -------------------------------------------------------------------------------- /tools/fake-apm-agent/README.md: -------------------------------------------------------------------------------- 1 | fake-apm-agent 2 | ============== 3 | 4 | Small tool implementing the [APM integration protocol specification][spec]. Allows debugging the 5 | APM integration code in the host agent without actually having to spin up a real APM agent. 6 | 7 | [spec]: https://github.com/elastic/apm/blob/main/specs/agents/universal-profiling-integration.md 8 | -------------------------------------------------------------------------------- /tools/fake-apm-agent/fake-apm-agent.c: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #include 5 | #include 6 | 7 | typedef int(*run_fake_apm_agent_t)(); 8 | 9 | int main() { 10 | // NOTE: `./` is necessary to make dlopen consider searching in local paths. 11 | void* handle = dlopen("./" LIB_NAME, RTLD_LAZY); 12 | if (!handle) { 13 | return 101; 14 | } 15 | 16 | run_fake_apm_agent_t fn = dlsym(handle, "run_fake_apm_agent"); 17 | if (dlerror() != NULL) { 18 | return 102; 19 | } 20 | 21 | return fn(); 22 | } 23 | -------------------------------------------------------------------------------- /tools/file_id.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | # This script computes the FileID as we do in Go code. 6 | 7 | # We must resolve symlinks before we can lookup the size of the file via `stat` 8 | file=$(readlink -f "$1") 9 | filesize=$(stat --printf="%s" "$file") 10 | 11 | hash=$(cat \ 12 | <(head -c 4096 "$file") \ 13 | <(tail -c 4096 "$file") \ 14 | <(printf $(printf "%.16x" $filesize | sed 's/\(..\)/\\x\1/g')) \ 15 | | sha256sum) 16 | 17 | echo "$hash" | head -c 32 18 | -------------------------------------------------------------------------------- /tools/stackdeltas/.gitignore: -------------------------------------------------------------------------------- 1 | stackdeltas 2 | -------------------------------------------------------------------------------- /tools/zstpak/.gitignore: -------------------------------------------------------------------------------- 1 | zstpak 2 | -------------------------------------------------------------------------------- /tools/zstpak/lib/zstpak_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package zstpak_test 5 | 6 | import ( 7 | "bytes" 8 | "os" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/require" 12 | 13 | "go.opentelemetry.io/ebpf-profiler/testsupport" 14 | zstpak "go.opentelemetry.io/ebpf-profiler/tools/zstpak/lib" 15 | ) 16 | 17 | func generateInputFile(seqLen uint8, outputSize uint64) []byte { 18 | out := make([]byte, 0, outputSize) 19 | for i := uint64(0); i < outputSize; i++ { 20 | out = append(out, byte(i%uint64(seqLen))) 21 | } 22 | 23 | return out 24 | } 25 | 26 | func testRandomAccesses(t *testing.T, seqLen uint8, fileSize uint64, 27 | chunkSize uint64) { 28 | file := generateInputFile(seqLen, fileSize) 29 | reader := bytes.NewReader(file) 30 | 31 | temp, err := os.CreateTemp(t.TempDir(), "") 32 | require.NoError(t, err) 33 | 34 | err = zstpak.CompressInto(reader, temp, chunkSize) 35 | require.NoError(t, err) 36 | err = temp.Close() 37 | require.NoError(t, err) 38 | 39 | zstReader, err := zstpak.Open(temp.Name()) 40 | require.NoError(t, err) 41 | 42 | testsupport.ValidateReadAtWrapperTransparency(t, 1000, file, zstReader) 43 | } 44 | 45 | func TestRandomAccess(t *testing.T) { 46 | // Repeat with 3 sets of mostly arbitrarily chosen parameters. 47 | testRandomAccesses(t, 128, 1024, 64) 48 | testRandomAccesses(t, 43, 1424, 444) 49 | testRandomAccesses(t, 13, 1049454, 8543) 50 | } 51 | -------------------------------------------------------------------------------- /tpbase/assembly_decode_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package tpbase // import "go.opentelemetry.io/ebpf-profiler/tpbase" 7 | 8 | func GetAnalyzers() []Analyzer { 9 | return arm64GetAnalyzers() 10 | } 11 | -------------------------------------------------------------------------------- /tpbase/fsbase_decode_amd64.h: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build amd64 5 | 6 | #ifndef __FSBASE_DECODE_X86_64__ 7 | #define __FSBASE_DECODE_X86_64__ 8 | 9 | #include 10 | 11 | uint32_t decode_fsbase_aout_dump_debugregs(const uint8_t* code, size_t codesz); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /tpbase/libc_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package tpbase // import "go.opentelemetry.io/ebpf-profiler/tpbase" 7 | 8 | import ( 9 | "errors" 10 | "unsafe" 11 | 12 | _ "go.opentelemetry.io/ebpf-profiler/zydis" // links Zydis 13 | ) 14 | 15 | // #cgo CFLAGS: -g -Wall 16 | // #include 17 | // #include "libc_decode_amd64.h" 18 | import "C" 19 | 20 | func ExtractTSDInfoX64_64(code []byte) (TSDInfo, error) { 21 | // function in order to properly analyze the code and deduce the fsbase offset. 22 | // The underlying logic uses the zydis library, hence the cgo call. 23 | val := uint32(C.decode_pthread_getspecific( 24 | (*C.uint8_t)(unsafe.Pointer(&code[0])), C.size_t(len(code)))) 25 | 26 | if val == 0 { 27 | return TSDInfo{}, errors.New("unable to determine libc info") 28 | } 29 | 30 | return TSDInfo{ 31 | Offset: int16(val & 0xffff), 32 | Multiplier: uint8(val >> 16), 33 | Indirect: uint8((val >> 24) & 1), 34 | }, nil 35 | } 36 | 37 | func ExtractTSDInfoNative(code []byte) (TSDInfo, error) { 38 | return ExtractTSDInfoX64_64(code) 39 | } 40 | -------------------------------------------------------------------------------- /tpbase/libc_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 2 | 3 | // Copyright The OpenTelemetry Authors 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package tpbase // import "go.opentelemetry.io/ebpf-profiler/tpbase" 7 | 8 | func ExtractTSDInfoX64_64(_ []byte) (TSDInfo, error) { 9 | return TSDInfo{}, errArchNotImplemented 10 | } 11 | 12 | func ExtractTSDInfoNative(code []byte) (TSDInfo, error) { 13 | return ExtractTSDInfoARM64(code) 14 | } 15 | -------------------------------------------------------------------------------- /tpbase/libc_decode_amd64.h: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build amd64 5 | 6 | #ifndef LIBC_DECODE_X86_64 7 | #define LIBC_DECODE_X86_64 8 | 9 | #include 10 | 11 | uint32_t decode_pthread_getspecific(const uint8_t* code, size_t codesz); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /tpbase/tpbase.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // tpbase implements disassembly analysis functions to extract needed data for 5 | // the Thread Pointer Base value handling. Code to analyze several Linux Kernel 6 | // architecture specific functions exist to extract offset of the TPBase value 7 | // relative to the 'struct task_struct'. This is needed to support Thread Local 8 | // Storage access in eBPF. 9 | 10 | package tpbase // import "go.opentelemetry.io/ebpf-profiler/tpbase" 11 | 12 | type Analyzer struct { 13 | // FunctionName is the kernel function which can be analyzed 14 | FunctionName string 15 | 16 | // Analyze can inspect the kernel function mentioned above for the Thread Pointer Base 17 | Analyze func([]byte) (uint32, error) 18 | } 19 | -------------------------------------------------------------------------------- /tracehandler/metrics.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package tracehandler // import "go.opentelemetry.io/ebpf-profiler/tracehandler" 5 | 6 | import "go.opentelemetry.io/ebpf-profiler/metrics" 7 | 8 | func (m *traceHandler) collectMetrics() { 9 | metrics.AddSlice([]metrics.Metric{ 10 | { 11 | ID: metrics.IDTraceCacheHit, 12 | Value: metrics.MetricValue(m.traceCacheHit), 13 | }, 14 | { 15 | ID: metrics.IDTraceCacheMiss, 16 | Value: metrics.MetricValue(m.traceCacheMiss), 17 | }, 18 | }) 19 | 20 | m.traceCacheHit = 0 21 | m.traceCacheMiss = 0 22 | } 23 | -------------------------------------------------------------------------------- /tracer/helper_test.go: -------------------------------------------------------------------------------- 1 | package tracer 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestReadCPURange(t *testing.T) { 10 | tests := map[string]struct { 11 | input string 12 | expected []int 13 | }{ 14 | "mixed": { 15 | input: "0,3-6,8-11", 16 | expected: []int{0, 3, 4, 5, 6, 8, 9, 10, 11}, 17 | }, 18 | "all": { 19 | input: "0-7", 20 | expected: []int{0, 1, 2, 3, 4, 5, 6, 7}, 21 | }, 22 | } 23 | 24 | for name, tc := range tests { 25 | name := name 26 | tc := tc 27 | t.Run(name, func(t *testing.T) { 28 | got, err := readCPURange(tc.input) 29 | require.NoError(t, err) 30 | require.Equal(t, tc.expected, got) 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tracer/probe_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | // Copyright The OpenTelemetry Authors 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | package tracer // import "go.opentelemetry.io/ebpf-profiler/tracer" 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | 14 | "golang.org/x/sys/unix" 15 | ) 16 | 17 | // ProbeBPFSyscall checks if the syscall EBPF is available on the system. 18 | func ProbeBPFSyscall() error { 19 | _, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(unix.BPF_PROG_TYPE_UNSPEC), uintptr(0), 0) 20 | if errNo == unix.ENOSYS { 21 | return errors.New("eBPF syscall is not available on your system") 22 | } 23 | return nil 24 | } 25 | 26 | // GetCurrentKernelVersion returns the major, minor and patch version of the kernel of the host 27 | // from the utsname struct. 28 | func GetCurrentKernelVersion() (major, minor, patch uint32, err error) { 29 | var uname unix.Utsname 30 | if err := unix.Uname(&uname); err != nil { 31 | return 0, 0, 0, fmt.Errorf("could not get Kernel Version: %v", err) 32 | } 33 | _, _ = fmt.Fscanf(bytes.NewReader(uname.Release[:]), "%d.%d.%d", &major, &minor, &patch) 34 | return major, minor, patch, nil 35 | } 36 | -------------------------------------------------------------------------------- /tracer/probe_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | // Copyright The OpenTelemetry Authors 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | package tracer // import "go.opentelemetry.io/ebpf-profiler/tracer" 8 | 9 | import ( 10 | "fmt" 11 | "runtime" 12 | ) 13 | 14 | // ProbeBPFSyscall checks if the syscall EBPF is available on the system. 15 | func ProbeBPFSyscall() error { 16 | return fmt.Errorf("eBPF is not available on your system %s", runtime.GOOS) 17 | } 18 | 19 | // GetCurrentKernelVersion returns an error for OS other than linux. 20 | func GetCurrentKernelVersion() (_, _, _ uint32, err error) { 21 | return 0, 0, 0, fmt.Errorf("kernel version detection is not supported on %s", 22 | runtime.GOOS) 23 | } 24 | -------------------------------------------------------------------------------- /tracer/tracepoints.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package tracer // import "go.opentelemetry.io/ebpf-profiler/tracer" 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/cilium/ebpf" 10 | "github.com/cilium/ebpf/link" 11 | "go.opentelemetry.io/ebpf-profiler/rlimit" 12 | ) 13 | 14 | // attachToTracepoint attaches an eBPF program of type tracepoint to a tracepoint in the kernel 15 | // defined by group and name. 16 | // Otherwise it returns an error. 17 | func (t *Tracer) attachToTracepoint(group, name string, prog *ebpf.Program) error { 18 | hp := hookPoint{ 19 | group: group, 20 | name: name, 21 | } 22 | hook, err := link.Tracepoint(hp.group, hp.name, prog, nil) 23 | if err != nil { 24 | return fmt.Errorf("failed to configure tracepoint on %#v: %v", hp, err) 25 | } 26 | t.hooks[hp] = hook 27 | return nil 28 | } 29 | 30 | // AttachSchedMonitor attaches a kprobe to the process scheduler. This hook detects the 31 | // exit of a process and enables us to clean up data we associated with this process. 32 | func (t *Tracer) AttachSchedMonitor() error { 33 | restoreRlimit, err := rlimit.MaximizeMemlock() 34 | if err != nil { 35 | return fmt.Errorf("failed to adjust rlimit: %v", err) 36 | } 37 | defer restoreRlimit() 38 | 39 | prog := t.ebpfProgs["tracepoint__sched_process_free"] 40 | return t.attachToTracepoint("sched", "sched_process_free", prog) 41 | } 42 | -------------------------------------------------------------------------------- /traceutil/traceutil.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package traceutil // import "go.opentelemetry.io/ebpf-profiler/traceutil" 5 | 6 | import ( 7 | "hash/fnv" 8 | "strconv" 9 | 10 | "go.opentelemetry.io/ebpf-profiler/libpf" 11 | ) 12 | 13 | // HashTrace calculates the hash of a trace and returns it. 14 | // Be aware that changes to this calculation will break the ability to 15 | // look backwards for the same TraceHash in our backend. 16 | func HashTrace(trace *libpf.Trace) libpf.TraceHash { 17 | var buf [24]byte 18 | h := fnv.New128a() 19 | for i := uint64(0); i < uint64(len(trace.Files)); i++ { 20 | _, _ = h.Write(trace.Files[i].Bytes()) 21 | // Using FormatUint() or putting AppendUint() into a function leads 22 | // to escaping to heap (allocation). 23 | _, _ = h.Write(strconv.AppendUint(buf[:0], uint64(trace.Linenos[i]), 10)) 24 | } 25 | // make instead of nil avoids a heap allocation 26 | traceHash, _ := libpf.TraceHashFromBytes(h.Sum(make([]byte, 0, 16))) 27 | return traceHash 28 | } 29 | -------------------------------------------------------------------------------- /traceutil/traceutil_test.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package traceutil 5 | 6 | import ( 7 | "testing" 8 | 9 | "go.opentelemetry.io/ebpf-profiler/libpf" 10 | "go.opentelemetry.io/ebpf-profiler/support" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | //nolint:testifylint 16 | func TestLibpfEBPFFrameMarkerEquality(t *testing.T) { 17 | assert.Equal(t, int(libpf.NativeFrame), support.FrameMarkerNative) 18 | assert.Equal(t, int(libpf.PythonFrame), support.FrameMarkerPython) 19 | assert.Equal(t, int(libpf.PHPFrame), support.FrameMarkerPHP) 20 | } 21 | 22 | func TestHashTrace(t *testing.T) { 23 | tests := map[string]struct { 24 | trace *libpf.Trace 25 | result libpf.TraceHash 26 | }{ 27 | "empty trace": { 28 | trace: &libpf.Trace{}, 29 | result: libpf.NewTraceHash(0x6c62272e07bb0142, 0x62b821756295c58d)}, 30 | "python trace": { 31 | trace: &libpf.Trace{ 32 | Linenos: []libpf.AddressOrLineno{0, 1, 2}, 33 | Files: []libpf.FileID{ 34 | libpf.NewFileID(0, 0), 35 | libpf.NewFileID(1, 1), 36 | libpf.NewFileID(2, 2), 37 | }, 38 | FrameTypes: []libpf.FrameType{ 39 | libpf.NativeFrame, 40 | libpf.NativeFrame, 41 | libpf.NativeFrame, 42 | }}, 43 | result: libpf.NewTraceHash(0x21c6fe4c62868856, 0xcf510596eab68dc8)}, 44 | } 45 | 46 | for name, testcase := range tests { 47 | name := name 48 | testcase := testcase 49 | t.Run(name, func(t *testing.T) { 50 | assert.Equal(t, testcase.result, HashTrace(testcase.trace)) 51 | }) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /util/util_test.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNextPowerOfTwo(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | input uint32 13 | want uint32 14 | }{ 15 | {name: "zero", input: 0, want: 1}, 16 | {name: "one", input: 1, want: 1}, 17 | {name: "two", input: 2, want: 2}, 18 | {name: "three", input: 3, want: 4}, 19 | {name: "four", input: 4, want: 4}, 20 | {name: "five", input: 5, want: 8}, 21 | {name: "six", input: 6, want: 8}, 22 | {name: "0x370", input: 0x370, want: 0x400}, 23 | } 24 | for _, tt := range tests { 25 | t.Run(tt.name, func(t *testing.T) { 26 | require.Equalf(t, tt.want, NextPowerOfTwo(tt.input), 27 | "NextPowerOfTwo() = %v, want %v", tt.want, tt.want) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /vc/vc.go: -------------------------------------------------------------------------------- 1 | // Copyright The OpenTelemetry Authors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package vc provides buildtime information. 5 | package vc // import "go.opentelemetry.io/ebpf-profiler/vc" 6 | 7 | var ( 8 | // The following variables are going to be set at link time using ldflags 9 | // and can be referenced later in the program. 10 | 11 | // revision of the service 12 | revision = "" 13 | // buildTimestamp, timestamp of the build 14 | buildTimestamp = "" 15 | // version in vX.Y.Z{-N-abbrev} format (via git-describe --tags) 16 | version = "" 17 | ) 18 | 19 | // Revision of the service. 20 | func Revision() string { 21 | return revision 22 | } 23 | 24 | // BuildTimestamp returns the timestamp of the build. 25 | func BuildTimestamp() string { 26 | return buildTimestamp 27 | } 28 | 29 | // Version in vX.Y.Z{-N-abbrev} format. 30 | func Version() string { 31 | return version 32 | } 33 | -------------------------------------------------------------------------------- /zydis/README.md: -------------------------------------------------------------------------------- 1 | Amalgamated Zydis 2 | ================= 3 | 4 | This directory contains the [amalgamated distribution] of Zydis. We ship 5 | the library as part of this repository to: 6 | 7 | - allow pulling in this repository as a library via the Go module system 8 | - automatically have it be compiled according to `GOOS` and `GOARCH` settings 9 | 10 | Current library version shipped in this directory: **v4.1.0** 11 | 12 | [amalgamated distribution]: https://github.com/zyantific/zydis?tab=readme-ov-file#amalgamated-distribution 13 | 14 | ## Updating the library 15 | 16 | - Look for the [latest Zydis release](https://github.com/zyantific/zydis/releases) 17 | - Download and extract the `zydis-amalgamated.tar.gz` release artifact 18 | - Replace `Zydis.h` and `Zydis.c` in this directory with the newly extracted variants 19 | -------------------------------------------------------------------------------- /zydis/zydis.go: -------------------------------------------------------------------------------- 1 | // Package zydis simply builds and links the Zydis library via CGo. 2 | package zydis // import "go.opentelemetry.io/ebpf-profiler/zydis" 3 | 4 | import "C" 5 | --------------------------------------------------------------------------------