Skip to content

Commit

Permalink
Treat go binaries without offsets as generic (1.9 branch patch) (#1477)
Browse files Browse the repository at this point in the history
* Treat go binaries without offsets as generic

There is a small corner case in which we detect no go offsets in a
target executable, but if that executable happens to have a ".gosyms"
section, we will end up classifying it as a Go executable, causing
issues. We attach an error in this case to have the attacher treat it as
a generic executable.

* Fixes panic on Go instrumentation

On ELF parse error, we return the list of missing fields, assuming that
we would stop the instrumentation. There is an edge case error on which
the missing fields set is empty so Beyla keeps with the instrumentation,
but the returned list of fields is nil.

* Treat Go proxies as generic binaries

In the case in which we have found offsets, but these are related to a
go proxy, we must set the error so that the attacher will treat this as
a regular binary.

---------

Co-authored-by: Mario Macias <[email protected]>
  • Loading branch information
rafaelroquetto and mariomac authored Dec 21, 2024
1 parent 6d9088b commit 62fb834
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 4 deletions.
4 changes: 3 additions & 1 deletion pkg/internal/discover/attacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,11 @@ func (ta *TraceAttacher) getTracer(ie *ebpf.Instrumentable) bool {
case svc.InstrumentableGolang:
// gets all the possible supported tracers for a go program, and filters out
// those whose symbols are not present in the ELF functions list
if ta.Cfg.Discovery.SkipGoSpecificTracers || ta.Cfg.Discovery.SystemWide || ie.InstrumentationError != nil {
if ta.Cfg.Discovery.SkipGoSpecificTracers || ta.Cfg.Discovery.SystemWide || ie.InstrumentationError != nil || ie.Offsets == nil {
if ie.InstrumentationError != nil {
ta.log.Warn("Unsupported Go program detected, using generic instrumentation", "error", ie.InstrumentationError)
} else if ie.Offsets == nil {
ta.log.Warn("Go program with null offsets detected, using generic instrumentation")
}
if ta.reusableTracer != nil {
// We need to do more than monitor PIDs. It's possible that this new
Expand Down
17 changes: 15 additions & 2 deletions pkg/internal/discover/typer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package discover

import (
"fmt"
"log/slog"
"strings"

Expand Down Expand Up @@ -124,6 +125,11 @@ func (t *typer) asInstrumentable(execElf *exec.FileInfo) ebpf.Instrumentable {
instrumentableCache.Add(execElf.Ino, InstrumentedExecutable{Type: svc.InstrumentableGolang, Offsets: offsets})
return ebpf.Instrumentable{Type: svc.InstrumentableGolang, FileInfo: execElf, Offsets: offsets}
}

if err == nil {
err = fmt.Errorf("identified as a Go proxy")
}

log.Debug("identified as a Go proxy")
} else {
log.Debug("identified as a generic, non-Go executable")
Expand All @@ -146,12 +152,19 @@ func (t *typer) asInstrumentable(execElf *exec.FileInfo) ebpf.Instrumentable {

detectedType := exec.FindProcLanguage(execElf.Pid, execElf.ELF, execElf.CmdExePath)

if detectedType == svc.InstrumentableGolang && err == nil {
log.Warn("ELF binary appears to be a Go program, but no offsets were found",
"comm", execElf.CmdExePath, "pid", execElf.Pid)

err = fmt.Errorf("could not find any Go offsets in Go binary %s", execElf.CmdExePath)
}

log.Debug("instrumented", "comm", execElf.CmdExePath, "pid", execElf.Pid,
"child", child, "language", detectedType.String())
// Return the instrumentable without offsets, as it is identified as a generic
// (or non-instrumentable Go proxy) executable
instrumentableCache.Add(execElf.Ino, InstrumentedExecutable{Type: detectedType, Offsets: offsets, InstrumentationError: err})
return ebpf.Instrumentable{Type: detectedType, FileInfo: execElf, ChildPids: child, InstrumentationError: err}
instrumentableCache.Add(execElf.Ino, InstrumentedExecutable{Type: detectedType, Offsets: nil, InstrumentationError: err})
return ebpf.Instrumentable{Type: detectedType, Offsets: nil, FileInfo: execElf, ChildPids: child, InstrumentationError: err}
}

func (t *typer) inspectOffsets(execElf *exec.FileInfo) (*goexec.Offsets, bool, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/internal/goexec/structmembers.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ func structMemberOffsetsFromDwarf(data *dwarf.Data) (FieldOffsets, map[GoOffset]
log.Debug("inspecting fields for struct type", "type", typeName)
if err := readMembers(reader, structMember.fields, expectedReturns, fieldOffsets); err != nil {
log.Debug("error reading DWARF info", "type", typeName, "error", err)
return nil, expectedReturns
return fieldOffsets, expectedReturns
}
}
}
Expand Down

0 comments on commit 62fb834

Please sign in to comment.