-
Notifications
You must be signed in to change notification settings - Fork 399
interpreter: add Golang #408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
5904478
interpreter: add Golang
florianl 4ed3800
fixup: add rust-components to more targets
florianl d995060
fixup: just log errors in executablemanager
florianl 7452f84
fixup: use native handling as fallback if Go symbolization fails
florianl a404307
fixup: drop IsGolang()
florianl 3aeb324
fixup: use interpreter.InstanceStubs
florianl 3cccd82
fixup: drop LRU and use resolved line number instead of pc for frameID
florianl 1210f6e
Update processmanager/manager.go
florianl d4fac4e
fixup: drop NOP comment
florianl 5ccf0b0
fixup: reword Golang to Go
florianl db9f246
fixup: s/Golang/Go/
florianl 62a70b3
fixup: fix frame ID
florianl 47c0680
fixup: en-/disable Go symbolization by flag
florianl 4aca444
fixup: add Go symbolization test
florianl b823392
fixup: avoid flaky tests
florianl e8d2582
Add and use ExtractAsFile for Process interface
fabled c4c0d33
fixup: build PointResolver in Loader()
florianl b948522
fixup: add coredump test
florianl 81c4ddd
fixup: make linter happy
florianl 74ad1f9
fixup: fix arm64 coredump tests
florianl 733570f
fixup: implement (goData)Unload()
florianl b93d090
fixup: support inlined frames
florianl 6356af7
fixup: apply feedback
florianl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package golang // import "go.opentelemetry.io/ebpf-profiler/interpreter/go" | ||
|
|
||
| /* | ||
| #cgo CFLAGS: -g -Wall | ||
| #include "../../rust-crates/symblib-capi/c/symblib.h" | ||
| #include <stdlib.h> | ||
| */ | ||
| import "C" | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "hash/fnv" | ||
| "sync/atomic" | ||
| "unsafe" | ||
|
|
||
| "go.opentelemetry.io/ebpf-profiler/host" | ||
| "go.opentelemetry.io/ebpf-profiler/interpreter" | ||
| "go.opentelemetry.io/ebpf-profiler/libpf" | ||
| "go.opentelemetry.io/ebpf-profiler/metrics" | ||
| "go.opentelemetry.io/ebpf-profiler/remotememory" | ||
| "go.opentelemetry.io/ebpf-profiler/reporter" | ||
| "go.opentelemetry.io/ebpf-profiler/successfailurecounter" | ||
| ) | ||
|
|
||
| var ( | ||
| // compiler check to make sure the needed interfaces are satisfied | ||
| _ interpreter.Data = &goData{} | ||
| _ interpreter.Instance = &goInstance{} | ||
| ) | ||
|
|
||
| type goData struct { | ||
| goExecutable *C.SymblibPointResolver | ||
| } | ||
|
|
||
| type goInstance struct { | ||
| interpreter.InstanceStubs | ||
|
|
||
| // Go symbolization metrics | ||
| successCount atomic.Uint64 | ||
| failCount atomic.Uint64 | ||
|
|
||
| d *goData | ||
| } | ||
|
|
||
| func Loader(_ interpreter.EbpfHandler, info *interpreter.LoaderInfo) ( | ||
| interpreter.Data, error) { | ||
| ef, err := info.GetELF() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if !ef.IsGolang() { | ||
| return nil, nil | ||
| } | ||
|
|
||
| exec, err := info.ExtractAsFile() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| executablePath := C.CString(exec) | ||
| defer C.free(unsafe.Pointer(executablePath)) | ||
|
|
||
| gd := &goData{} | ||
|
|
||
| //nolint:gocritic | ||
| status := C.symblib_goruntime_new(executablePath, &gd.goExecutable) | ||
| if status != C.SYMBLIB_OK { | ||
| return nil, fmt.Errorf("failed to create point resolver for '%s': %d", | ||
| exec, status) | ||
| } | ||
|
|
||
| return gd, nil | ||
| } | ||
|
|
||
| func (g *goData) Attach(_ interpreter.EbpfHandler, _ libpf.PID, | ||
| _ libpf.Address, _ remotememory.RemoteMemory) (interpreter.Instance, error) { | ||
| return &goInstance{ | ||
| d: g, | ||
| }, nil | ||
| } | ||
|
|
||
| func (g *goData) Unload(_ interpreter.EbpfHandler) { | ||
| if g.goExecutable != nil { | ||
| C.symblib_goruntime_free(g.goExecutable) | ||
| g.goExecutable = nil | ||
| } | ||
| } | ||
|
|
||
| func (g *goInstance) GetAndResetMetrics() ([]metrics.Metric, error) { | ||
| return []metrics.Metric{ | ||
| { | ||
| ID: metrics.IDGoSymbolizationSuccess, | ||
| Value: metrics.MetricValue(g.successCount.Swap(0)), | ||
| }, | ||
| { | ||
| ID: metrics.IDGoSymbolizationFailure, | ||
| Value: metrics.MetricValue(g.failCount.Swap(0)), | ||
| }, | ||
| }, nil | ||
| } | ||
|
|
||
| // Detach is a NOP for goInstance. | ||
| func (g *goInstance) Detach(_ interpreter.EbpfHandler, _ libpf.PID) error { | ||
| return nil | ||
| } | ||
|
|
||
| func (g *goInstance) Symbolize(symbolReporter reporter.SymbolReporter, frame *host.Frame, | ||
|
florianl marked this conversation as resolved.
|
||
| trace *libpf.Trace) error { | ||
| if !frame.Type.IsInterpType(libpf.Native) { | ||
| return interpreter.ErrMismatchInterpreterType | ||
| } | ||
| sfCounter := successfailurecounter.New(&g.successCount, &g.failCount) | ||
| defer sfCounter.DefaultToFailure() | ||
|
|
||
| if g.d.goExecutable == nil { | ||
| return errors.New("point resolver is out of scope") | ||
| } | ||
|
|
||
| var symbols *C.SymblibSlice_SymblibResolvedSymbol | ||
| defer C.symblib_slice_symblibresolved_symbol_free(symbols) | ||
|
|
||
| //nolint:gocritic | ||
| status := C.symblib_point_resolver_symbols_for_pc(g.d.goExecutable, | ||
| C.uint64_t(frame.Lineno), &symbols) | ||
| if status != C.SYMBLIB_OK { | ||
| return fmt.Errorf("failed to do point lookup at 0x%x: %d", | ||
| frame.Lineno, status) | ||
| } | ||
|
|
||
| // Access resolved symbols | ||
| symbolsSlice := unsafe.Slice((*C.SymblibResolvedSymbol)(unsafe.Pointer(symbols.data)), | ||
| symbols.len) | ||
| if len(symbolsSlice) == 0 { | ||
| return fmt.Errorf("failed to symbolize 0x%x", frame.Lineno) | ||
| } | ||
|
|
||
| frameFileBytes := []byte(frame.File.StringNoQuotes()) | ||
| for i := 0; i < len(symbolsSlice); i++ { | ||
| lineNo := libpf.SourceLineno(symbolsSlice[i].line_number) | ||
| funcName := C.GoString(symbolsSlice[i].function_name) | ||
| sourceFile := C.GoString(symbolsSlice[i].file_name) | ||
|
|
||
| // The fnv hash Write() method calls cannot fail, so it's safe to ignore the errors. | ||
| h := fnv.New128a() | ||
| _, _ = h.Write(frameFileBytes) | ||
| _, _ = h.Write([]byte(funcName)) | ||
| _, _ = h.Write([]byte(sourceFile)) | ||
| fileID, err := libpf.FileIDFromBytes(h.Sum(nil)) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create a file ID: %v", err) | ||
| } | ||
|
|
||
| frameID := libpf.NewFrameID(fileID, libpf.AddressOrLineno(lineNo)) | ||
|
|
||
| trace.AppendFrameID(libpf.GoFrame, frameID) | ||
|
|
||
| symbolReporter.FrameMetadata(&reporter.FrameMetadataArgs{ | ||
| FrameID: frameID, | ||
| FunctionName: funcName, | ||
| SourceFile: sourceFile, | ||
| SourceLine: lineNo, | ||
| }) | ||
| } | ||
|
|
||
| sfCounter.ReportSuccess() | ||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| //go:build amd64 | ||
|
|
||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package golang // import "go.opentelemetry.io/ebpf-profiler/interpreter/go" | ||
|
|
||
| /* | ||
| #cgo LDFLAGS: ${SRCDIR}/../../target/x86_64-unknown-linux-musl/release/libsymblib_capi.a | ||
| */ | ||
| import "C" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| //go:build arm64 | ||
|
|
||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package golang // import "go.opentelemetry.io/ebpf-profiler/interpreter/go" | ||
|
|
||
| /* | ||
| #cgo LDFLAGS: ${SRCDIR}/../../target/aarch64-unknown-linux-musl/release/libsymblib_capi.a | ||
| */ | ||
| import "C" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| { | ||
| "coredump-ref": "ad99fdc13a9fd30c511ae87fbd2f0d4ba8c16af65a691cce39dc9031f04b26f4", | ||
| "threads": [ | ||
| { | ||
| "lwp": 2683, | ||
| "frames": [ | ||
| "internal/runtime/syscall.Syscall6+0 in /usr/local/go/src/internal/runtime/syscall/asm_linux_amd64.s:36", | ||
| "syscall.RawSyscall6+0 in /usr/local/go/src/syscall/syscall_linux.go:66", | ||
| "syscall.Syscall+0 in /usr/local/go/src/syscall/syscall_linux.go:86", | ||
| "syscall.write+0 in /usr/local/go/src/syscall/zsyscall_linux_amd64.go:964", | ||
| "internal/poll.(*FD).Write+0 in /usr/local/go/src/syscall/syscall_unix.go:211", | ||
| "os.(*File).Write+0 in /usr/local/go/src/os/file.go:196", | ||
| "fmt.Fprintln+0 in /usr/local/go/src/fmt/print.go:305", | ||
| "main.hello+0 in /home/ec2-user/testsources/go/hello.go:14", | ||
| "main.main+0 in /home/ec2-user/testsources/go/hello.go:50", | ||
| "runtime.main+0 in /usr/local/go/src/internal/runtime/atomic/types.go:194", | ||
| "runtime.goexit+0 in /usr/local/go/src/runtime/asm_amd64.s:1701" | ||
| ] | ||
| }, | ||
| { | ||
| "lwp": 2684, | ||
| "frames": [ | ||
| "runtime.usleep+0 in /usr/local/go/src/runtime/sys_linux_amd64.s:135", | ||
| "runtime.sysmon+0 in /usr/local/go/src/runtime/proc.go:6108", | ||
| "runtime.sysmon+0 in /usr/local/go/src/runtime/proc.go:6108", | ||
| "runtime.mstart1+0 in /usr/local/go/src/runtime/proc.go:1855", | ||
| "runtime.mstart0+0 in /usr/local/go/src/runtime/proc.go:1817", | ||
| "runtime.mstart+0 in /usr/local/go/src/runtime/asm_amd64.s:396" | ||
| ] | ||
| }, | ||
| { | ||
| "lwp": 2685, | ||
| "frames": [ | ||
| "runtime.futex+0 in /usr/local/go/src/runtime/sys_linux_amd64.s:558", | ||
| "runtime.futexsleep+0 in /usr/local/go/src/runtime/os_linux.go:75", | ||
| "runtime.notesleep+0 in /usr/local/go/src/runtime/lock_futex.go:48", | ||
| "runtime.stopm+0 in /usr/local/go/src/runtime/proc.go:1888", | ||
| "runtime.findRunnable+0 in /usr/local/go/src/runtime/proc.go:3279", | ||
| "runtime.schedule+0 in /usr/local/go/src/runtime/proc.go:4017", | ||
| "runtime.goschedImpl+0 in /usr/local/go/src/runtime/proc.go:4176", | ||
| "runtime.gopreempt_m+0 in /usr/local/go/src/runtime/proc.go:4193", | ||
| "runtime.mcall+0 in /usr/local/go/src/runtime/asm_amd64.s:463" | ||
| ] | ||
| }, | ||
| { | ||
| "lwp": 2686, | ||
| "frames": [ | ||
| "runtime.futex+0 in /usr/local/go/src/runtime/sys_linux_amd64.s:558", | ||
| "runtime.futexsleep+0 in /usr/local/go/src/runtime/os_linux.go:75", | ||
| "runtime.notesleep+0 in /usr/local/go/src/runtime/lock_futex.go:48", | ||
| "runtime.stopm+0 in /usr/local/go/src/runtime/proc.go:1888", | ||
| "runtime.exitsyscall0+0 in /usr/local/go/src/runtime/proc.go:4875", | ||
| "runtime.mcall+0 in /usr/local/go/src/runtime/asm_amd64.s:463" | ||
| ] | ||
| } | ||
| ], | ||
| "modules": [ | ||
| { | ||
| "ref": "cfe34afe8ed0115e552d0e94cf7bd46186deb8c3775b310204f194a0b5f67cd5", | ||
| "local-path": "/home/ec2-user/testsources/go/hello" | ||
| } | ||
| ] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.